mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-10 19:56:59 +03:00
Add support for Django 3.1 JSONField (#7467)
Django 3.1 adds a new generic JSONField to replace the PostgreSQL-specific one. This adds support for the new field type, which should behave the same as the existing PostgreSQL field. Django's new JSONField also includes support for a custom "decoder", so add support for that in the serializer field.
This commit is contained in:
parent
7f3a3557a0
commit
b3e02592d0
|
@ -1758,6 +1758,7 @@ class JSONField(Field):
|
|||
def __init__(self, *args, **kwargs):
|
||||
self.binary = kwargs.pop('binary', False)
|
||||
self.encoder = kwargs.pop('encoder', None)
|
||||
self.decoder = kwargs.pop('decoder', None)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def get_value(self, dictionary):
|
||||
|
@ -1777,7 +1778,7 @@ class JSONField(Field):
|
|||
if self.binary or getattr(data, 'is_json_string', False):
|
||||
if isinstance(data, bytes):
|
||||
data = data.decode()
|
||||
return json.loads(data)
|
||||
return json.loads(data, cls=self.decoder)
|
||||
else:
|
||||
json.dumps(data, cls=self.encoder)
|
||||
except (TypeError, ValueError):
|
||||
|
|
|
@ -884,6 +884,8 @@ class ModelSerializer(Serializer):
|
|||
models.GenericIPAddressField: IPAddressField,
|
||||
models.FilePathField: FilePathField,
|
||||
}
|
||||
if hasattr(models, 'JSONField'):
|
||||
serializer_field_mapping[models.JSONField] = JSONField
|
||||
if postgres_fields:
|
||||
serializer_field_mapping[postgres_fields.HStoreField] = HStoreField
|
||||
serializer_field_mapping[postgres_fields.ArrayField] = ListField
|
||||
|
@ -1242,10 +1244,13 @@ class ModelSerializer(Serializer):
|
|||
# `allow_blank` is only valid for textual fields.
|
||||
field_kwargs.pop('allow_blank', None)
|
||||
|
||||
if postgres_fields and isinstance(model_field, postgres_fields.JSONField):
|
||||
is_django_jsonfield = hasattr(models, 'JSONField') and isinstance(model_field, models.JSONField)
|
||||
if (postgres_fields and isinstance(model_field, postgres_fields.JSONField)) or is_django_jsonfield:
|
||||
# Populate the `encoder` argument of `JSONField` instances generated
|
||||
# for the PostgreSQL specific `JSONField`.
|
||||
# for the model `JSONField`.
|
||||
field_kwargs['encoder'] = getattr(model_field, 'encoder', None)
|
||||
if is_django_jsonfield:
|
||||
field_kwargs['decoder'] = getattr(model_field, 'decoder', None)
|
||||
|
||||
if postgres_fields and isinstance(model_field, postgres_fields.ArrayField):
|
||||
# Populate the `child` argument on `ListField` instances generated
|
||||
|
|
|
@ -92,7 +92,8 @@ def get_field_kwargs(field_name, model_field):
|
|||
kwargs['allow_unicode'] = model_field.allow_unicode
|
||||
|
||||
if isinstance(model_field, models.TextField) and not model_field.choices or \
|
||||
(postgres_fields and isinstance(model_field, postgres_fields.JSONField)):
|
||||
(postgres_fields and isinstance(model_field, postgres_fields.JSONField)) or \
|
||||
(hasattr(models, 'JSONField') and isinstance(model_field, models.JSONField)):
|
||||
kwargs['style'] = {'base_template': 'textarea.html'}
|
||||
|
||||
if isinstance(model_field, models.AutoField) or not model_field.editable:
|
||||
|
|
|
@ -7,6 +7,7 @@ an appropriate set of serializer fields for each case.
|
|||
"""
|
||||
import datetime
|
||||
import decimal
|
||||
import json # noqa
|
||||
import sys
|
||||
import tempfile
|
||||
from collections import OrderedDict
|
||||
|
@ -478,6 +479,7 @@ class TestPosgresFieldsMapping(TestCase):
|
|||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
|
||||
@pytest.mark.skipif(hasattr(models, 'JSONField'), reason='has models.JSONField')
|
||||
def test_json_field(self):
|
||||
class JSONFieldModel(models.Model):
|
||||
json_field = postgres_fields.JSONField()
|
||||
|
@ -496,6 +498,30 @@ class TestPosgresFieldsMapping(TestCase):
|
|||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
|
||||
|
||||
class CustomJSONDecoder(json.JSONDecoder):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.skipif(not hasattr(models, 'JSONField'), reason='no models.JSONField')
|
||||
class TestDjangoJSONFieldMapping(TestCase):
|
||||
def test_json_field(self):
|
||||
class JSONFieldModel(models.Model):
|
||||
json_field = models.JSONField()
|
||||
json_field_with_encoder = models.JSONField(encoder=DjangoJSONEncoder, decoder=CustomJSONDecoder)
|
||||
|
||||
class TestSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = JSONFieldModel
|
||||
fields = ['json_field', 'json_field_with_encoder']
|
||||
|
||||
expected = dedent("""
|
||||
TestSerializer():
|
||||
json_field = JSONField(decoder=None, encoder=None, style={'base_template': 'textarea.html'})
|
||||
json_field_with_encoder = JSONField(decoder=<class 'tests.test_model_serializer.CustomJSONDecoder'>, encoder=<class 'django.core.serializers.json.DjangoJSONEncoder'>, style={'base_template': 'textarea.html'})
|
||||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
|
||||
|
||||
# Tests for relational field mappings.
|
||||
# ------------------------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user