-
Type:
New Feature
-
Resolution: Unresolved
-
Priority:
Minor - P4
-
None
-
Affects Version/s: None
-
Component/s: django
-
None
As requested on the community forum, it would be useful to have JSONField support BSON data types. Unfortunately, this may require a custom field or a change to Django's built-in JSONField.
Alternatively, I worked up a quick example using a custom decoder/encoder that appears to work to some extent:
diff --git a/django_mongodb_backend/operations.py b/django_mongodb_backend/operations.py index cb1e93d..dcdf7fb 100644 --- a/django_mongodb_backend/operations.py +++ b/django_mongodb_backend/operations.py @@ -147,7 +147,9 @@ class DatabaseOperations(BaseDatabaseOperations): Convert dict data to a string so that JSONField.from_db_value() can decode it using json.loads(). """ - return json.dumps(value) + target = getattr(expression, 'target', None) + encoder = target.encoder if target else None + return json.dumps(value, cls=encoder) def convert_timefield_value(self, value, expression, connection): if value is not None: diff --git a/tests/model_fields_/models.py b/tests/model_fields_/models.py index b25b94a..b8fa3c0 100644 --- a/tests/model_fields_/models.py +++ b/tests/model_fields_/models.py @@ -6,6 +6,25 @@ from django_mongodb_backend.fields import ArrayField, EmbeddedModelField, Object from django_mongodb_backend.models import EmbeddedModel +import json +from bson import json_util + + +class BSONEncoder(json.JSONEncoder): + def encode(self, obj): + return json_util.dumps(obj) + + +class BSONDecoder(json.JSONDecoder): + def decode(self, obj): + return json_util.loads(obj) + + +# JSONField +class JSONModel(models.Model): + value = models.JSONField(encoder=BSONEncoder, decoder=BSONDecoder) + + # ObjectIdField class ObjectIdModel(models.Model): field = ObjectIdField() diff --git a/tests/model_fields_/test_jsonfield.py b/tests/model_fields_/test_jsonfield.py new file mode 100644 index 0000000..a860b7b --- /dev/null +++ b/tests/model_fields_/test_jsonfield.py @@ -0,0 +1,15 @@ +from django.db.models import JSONField +from django.test import TestCase +from bson import ObjectId + +from .models import JSONModel + + +class TestSaveLoad(TestCase): + def test_null(self): + object_id = ObjectId() + value = {"key": object_id} + obj = JSONModel(value=value) + obj.save() + obj.refresh_from_db() + self.assertEqual(obj.value, value)
In order for querying to work as expected, the field would require custom Django lookups to prepare BSON types into the dictionary format the bson.json_util.dumps() outputs, e.g. {}{"$oid": "67d5f6f5188e40f99400bc15"} for ObjectId.