diff options
| author | Tom Christie | 2014-12-19 12:18:40 +0000 | 
|---|---|---|
| committer | Tom Christie | 2014-12-19 12:18:40 +0000 | 
| commit | 6d907cde9a90aad76acb00482a1d70550bb95ccd (patch) | |
| tree | 96f2de383af71626bfc12e322c33965f632b7532 | |
| parent | ba753a7536fe5e0b38d25b6b1ded2f504b5f8cca (diff) | |
| download | django-rest-framework-6d907cde9a90aad76acb00482a1d70550bb95ccd.tar.bz2 | |
get_field_names, get_default_field_names
| -rw-r--r-- | rest_framework/serializers.py | 102 | ||||
| -rw-r--r-- | tests/test_model_serializer.py | 8 | 
2 files changed, 76 insertions, 34 deletions
| diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 52ea5b0b..b391a94e 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -883,41 +883,14 @@ class ModelSerializer(Serializer):          ret = OrderedDict()          model = getattr(self.Meta, 'model') -        fields = getattr(self.Meta, 'fields', None) -        exclude = getattr(self.Meta, 'exclude', None)          depth = getattr(self.Meta, 'depth', 0)          extra_kwargs = getattr(self.Meta, 'extra_kwargs', {}) - -        if 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)): -            raise TypeError( -                'The `exclude` option must be a list or tuple. Got %s.' % -                type(exclude).__name__ -            ) - -        assert not (fields and exclude), "Cannot set both 'fields' and 'exclude'." -          extra_kwargs = self._include_additional_options(extra_kwargs)          # Retrieve metadata about fields & relationships on the model class.          info = model_meta.get_field_info(model) -        # Use the default set of field names if none is supplied explicitly. -        if fields is None: -            fields = self._get_default_field_names(declared_fields, info) -            exclude = getattr(self.Meta, 'exclude', None) -            if exclude is not None: -                for field_name in exclude: -                    assert field_name in fields, ( -                        'The field in the `exclude` option must be a model field. Got %s.' % -                        field_name -                    ) -                    fields.remove(field_name) +        fields = self.get_field_names(declared_fields, info)          # Determine the set of model fields, and the fields that they map to.          # We actually only need this to deal with the slightly awkward case @@ -1133,7 +1106,72 @@ class ModelSerializer(Serializer):          return extra_kwargs -    def _get_default_field_names(self, declared_fields, model_info): +    def get_field_names(self, declared_fields, info): +        """ +        Returns the list of all field names that should be created when +        instantiating this serializer class. This is based on the default +        set of fields, but also takes into account the `Meta.fields` or +        `Meta.exclude` options if they have been specified. +        """ +        fields = getattr(self.Meta, 'fields', None) +        exclude = getattr(self.Meta, 'exclude', None) + +        if 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)): +            raise TypeError( +                'The `exclude` option must be a list or tuple. Got %s.' % +                type(exclude).__name__ +            ) + +        assert not (fields and exclude), ( +            "Cannot set both 'fields' and 'exclude' options on " +            "serializer {serializer_class}.".format( +                serializer_class=self.__class__.__name__ +            ) +        ) + +        if fields is not None: +            # Ensure that all declared fields have also been included in the +            # `Meta.fields` option. +            for field_name in declared_fields: +                assert field_name in fields, ( +                    "The field '{field_name}' was declared on serializer " +                    "{serializer_class}, but has not been included in the " +                    "'fields' option.".format( +                        field_name=field_name, +                        serializer_class=self.__class__.__name__ +                    ) +                ) +            return fields + +        # Use the default set of field names if `Meta.fields` is not specified. +        fields = self.get_default_field_names(declared_fields, info) + +        if exclude is not None: +            # If `Meta.exclude` is included, then remove those fields. +            for field_name in exclude: +                assert field_name in fields, ( +                    "The field '{field_name}' was include on serializer " +                    "{serializer_class} in the 'exclude' option, but does " +                    "not match any model field.".format( +                        field_name=field_name, +                        serializer_class=self.__class__.__name__ +                    ) +                ) +                fields.remove(field_name) + +        return fields + +    def get_default_field_names(self, declared_fields, model_info): +        """ +        Return the default list of field names that will be used if the +        `Meta.fields` option is not specified. +        """          return (              [model_info.pk.name] +              list(declared_fields.keys()) + @@ -1160,7 +1198,11 @@ class HyperlinkedModelSerializer(ModelSerializer):      """      _related_class = HyperlinkedRelatedField -    def _get_default_field_names(self, declared_fields, model_info): +    def get_default_field_names(self, declared_fields, model_info): +        """ +        Return the default list of field names that will be used if the +        `Meta.fields` option is not specified. +        """          return (              [api_settings.URL_FIELD_NAME] +              list(declared_fields.keys()) + diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index da79164a..5c56c8db 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -221,11 +221,11 @@ class TestRegularFieldMappings(TestCase):                  model = RegularFieldsModel                  fields = ('auto_field',) -        with self.assertRaises(ImproperlyConfigured) as excinfo: +        with self.assertRaises(AssertionError) as excinfo:              TestSerializer().fields          expected = ( -            'Field `missing` has been declared on serializer ' -            '`TestSerializer`, but is missing from `Meta.fields`.' +            "The field 'missing' was declared on serializer TestSerializer, " +            "but has not been included in the 'fields' option."          )          assert str(excinfo.exception) == expected @@ -607,5 +607,5 @@ class TestSerializerMetaClass(TestCase):          exception = result.exception          self.assertEqual(              str(exception), -            "Cannot set both 'fields' and 'exclude'." +            "Cannot set both 'fields' and 'exclude' options on serializer ExampleSerializer."          ) | 
