Commit f87573ff by Tom Christie

Merge pull request #3345 from jpadilla/fields

Update ModelSerializer 'fields'/'exclude'/'__all__' behavior
parents 78632849 9dd1b251
...@@ -432,6 +432,7 @@ Declaring a `ModelSerializer` looks like this: ...@@ -432,6 +432,7 @@ Declaring a `ModelSerializer` looks like this:
class AccountSerializer(serializers.ModelSerializer): class AccountSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Account model = Account
fields = ('id', 'account_name', 'users', 'created')
By default, all the model fields on the class will be mapped to a corresponding serializer fields. By default, all the model fields on the class will be mapped to a corresponding serializer fields.
...@@ -453,7 +454,7 @@ To do so, open the Django shell, using `python manage.py shell`, then import the ...@@ -453,7 +454,7 @@ To do so, open the Django shell, using `python manage.py shell`, then import the
## Specifying which fields to include ## Specifying which fields to include
If you only want a subset of the default fields to be used in a model serializer, you can do so using `fields` or `exclude` options, just as you would with a `ModelForm`. If you only want a subset of the default fields to be used in a model serializer, you can do so using `fields` or `exclude` options, just as you would with a `ModelForm`. It is strongly recommended that you explicitly set all fields that should be serialized using the `fields` attribute. This will make it less likely to result in unintentionally exposing data when your models change.
For example: For example:
...@@ -462,7 +463,27 @@ For example: ...@@ -462,7 +463,27 @@ For example:
model = Account model = Account
fields = ('id', 'account_name', 'users', 'created') fields = ('id', 'account_name', 'users', 'created')
The names in the `fields` option will normally map to model fields on the model class. You can also set the `fields` attribute to the special value `'__all__'` to indicate that all fields in the model should be used.
For example:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = '__all__'
You can set the `exclude` attribute of the to a list of fields to be excluded from the serializer.
For example:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
exclude = ('users',)
In the example above, if the `Account` model had 3 fields `account_name`, `users`, and `created`, this will result in the fields `account_name` and `created` to be serialized.
The names in the `fields` and `exclude` attributes will normally map to model fields on the model class.
Alternatively names in the `fields` options can map to properties or methods which take no arguments that exist on the model class. Alternatively names in the `fields` options can map to properties or methods which take no arguments that exist on the model class.
......
...@@ -12,6 +12,8 @@ response content is handled by parsers and renderers. ...@@ -12,6 +12,8 @@ response content is handled by parsers and renderers.
""" """
from __future__ import unicode_literals from __future__ import unicode_literals
import warnings
from django.db import models from django.db import models
from django.db.models.fields import Field as DjangoModelField from django.db.models.fields import Field as DjangoModelField
from django.db.models.fields import FieldDoesNotExist from django.db.models.fields import FieldDoesNotExist
...@@ -51,6 +53,8 @@ LIST_SERIALIZER_KWARGS = ( ...@@ -51,6 +53,8 @@ LIST_SERIALIZER_KWARGS = (
'instance', 'data', 'partial', 'context', 'allow_null' 'instance', 'data', 'partial', 'context', 'allow_null'
) )
ALL_FIELDS = '__all__'
# BaseSerializer # BaseSerializer
# -------------- # --------------
...@@ -943,13 +947,13 @@ class ModelSerializer(Serializer): ...@@ -943,13 +947,13 @@ class ModelSerializer(Serializer):
fields = getattr(self.Meta, 'fields', None) fields = getattr(self.Meta, 'fields', None)
exclude = getattr(self.Meta, 'exclude', 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( raise TypeError(
'The `fields` option must be a list or tuple. Got %s.' % 'The `fields` option must be a list or tuple. Got %s.' %
type(fields).__name__ 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( raise TypeError(
'The `exclude` option must be a list or tuple. Got %s.' % 'The `exclude` option must be a list or tuple. Got %s.' %
type(exclude).__name__ type(exclude).__name__
...@@ -962,6 +966,19 @@ class ModelSerializer(Serializer): ...@@ -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: if fields is not None:
# Ensure that all declared fields have also been included in the # Ensure that all declared fields have also been included in the
# `Meta.fields` option. # `Meta.fields` option.
......
...@@ -321,6 +321,21 @@ class TestRegularFieldMappings(TestCase): ...@@ -321,6 +321,21 @@ class TestRegularFieldMappings(TestCase):
ExampleSerializer() 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), @pytest.mark.skipif(django.VERSION < (1, 8),
reason='DurationField is only available for django1.8+') reason='DurationField is only available for django1.8+')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment