diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index c7d4405c5..acaf3bef7 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -12,6 +12,8 @@ response content is handled by parsers and renderers. """ from __future__ import unicode_literals +import warnings + from django.db import models from django.db.models.fields import Field as DjangoModelField from django.db.models.fields import FieldDoesNotExist @@ -51,6 +53,8 @@ LIST_SERIALIZER_KWARGS = ( 'instance', 'data', 'partial', 'context', 'allow_null' ) +ALL_FIELDS = '__all__' + # BaseSerializer # -------------- @@ -943,13 +947,13 @@ class ModelSerializer(Serializer): fields = getattr(self.Meta, 'fields', None) exclude = getattr(self.Meta, 'exclude', None) - if fields and not isinstance(fields, (list, tuple)): + if fields and fields != ALL_FIELDS and not isinstance(fields, (list, tuple)): raise TypeError( 'The `fields` option must be a list or tuple. Got %s.' % type(fields).__name__ ) - if exclude and not isinstance(exclude, (list, tuple)): + if exclude and exclude != ALL_FIELDS and not isinstance(exclude, (list, tuple)): raise TypeError( 'The `exclude` option must be a list or tuple. Got %s.' % type(exclude).__name__ @@ -962,6 +966,19 @@ class ModelSerializer(Serializer): ) ) + if fields is None and exclude is None: + warnings.warn( + "Creating a ModelSerializer without either the 'fields' attribute " + "or the 'exclude' attribute will be prohibited. " + "The {serializer_class} serializer needs updating.".format( + serializer_class=self.__class__.__name__ + ), + PendingDeprecationWarning + ) + + if fields == ALL_FIELDS: + fields = None + if fields is not None: # Ensure that all declared fields have also been included in the # `Meta.fields` option. diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index 777b956c4..89557fa1d 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -321,6 +321,21 @@ class TestRegularFieldMappings(TestCase): ExampleSerializer() + def test_fields_and_exclude_behavior(self): + class ImplicitFieldsSerializer(serializers.ModelSerializer): + class Meta: + model = RegularFieldsModel + + class ExplicitFieldsSerializer(serializers.ModelSerializer): + class Meta: + model = RegularFieldsModel + fields = '__all__' + + implicit = ImplicitFieldsSerializer() + explicit = ExplicitFieldsSerializer() + + assert implicit.data == explicit.data + @pytest.mark.skipif(django.VERSION < (1, 8), reason='DurationField is only available for django1.8+')