Add support for field_classes on ModelSerializer

This commit is contained in:
Mattias Lindvall 2020-10-16 17:34:08 +02:00
parent 04e0c2b9ab
commit 7f02a813af
No known key found for this signature in database
GPG Key ID: 8939D51376EEF212
3 changed files with 51 additions and 0 deletions

View File

@ -527,6 +527,21 @@ You can add extra fields to a `ModelSerializer` or override the default fields b
Extra fields can correspond to any property or callable on the model.
## Specifying field classes
In order to override the field class only, and still get the field kwargs set dynamically, you may use the `field_classes`
Meta option.
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['account_name']
field_classes = {'account_name': AccountNameField}
Note that the field class that you use needs to support whatever kwargs the serializer determines to use for this field.
Typically, you want your custom field class to inherit from the appropriate built in field class.
For example, the custom `AccountNameField` could inherit from the built in `CharField`.
## Specifying read only fields
You may wish to specify multiple fields as read-only. Instead of adding each field explicitly with the `read_only=True` attribute, you may use the shortcut Meta option, `read_only_fields`.

View File

@ -1054,6 +1054,11 @@ class ModelSerializer(Serializer):
source, info, model, depth
)
# Override field_class by classes defined in `Meta.field_classes`.
field_class = self.get_field_class(
source, info, model, field_class
)
# Include any kwargs defined in `Meta.extra_kwargs`
field_kwargs = self.include_extra_kwargs(
field_kwargs, extra_field_kwargs
@ -1319,6 +1324,17 @@ class ModelSerializer(Serializer):
(field_name, model_class.__name__)
)
def get_field_class(self, field_name, info, model_class, field_class):
"""
Get field class from 'field_classes', or use the default.
"""
field_classes = getattr(self.Meta, 'field_classes', {})
if field_name in field_classes:
return field_classes[field_name]
return field_class
def include_extra_kwargs(self, kwargs, extra_kwargs):
"""
Include any 'extra_kwargs' that have been included for this field,

View File

@ -271,6 +271,26 @@ class TestRegularFieldMappings(TestCase):
""")
self.assertEqual(repr(TestSerializer()), expected)
def test_field_classes(self):
"""
Ensure `field_classes` do override the field class.
"""
class CustomCharField(serializers.CharField):
pass
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = RegularFieldsModel
fields = ('auto_field', 'char_field')
field_classes = {'char_field': CustomCharField}
expected = dedent("""
TestSerializer():
auto_field = IntegerField(read_only=True)
char_field = CustomCharField(max_length=100)
""")
self.assertEqual(repr(TestSerializer()), expected)
def test_extra_field_kwargs(self):
"""
Ensure `extra_kwargs` are passed to generated fields.