Christoffer
Christoffer

Reputation: 7993

Can the same nested serializer be used to output different data - Django Rest Framework

If I have something like this:

class SnippetSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.Field(source='owner.username')

    class Meta:
        model = Snippet
        fields = ('url', 'owner', 'title', 'code', 'linenos', 'language', 'style')

class UserSerializer(serializers.HyperlinkedModelSerializer):
    snippets = SnippetSerializer()

    class Meta:
        model = User
        fields = ('url', 'username', 'snippets')

Then it will output all the fields defined in the SnippetSerializer. But I want to be able to do something like this:

snippets = SnippetSerializer(fields=('title', 'code'))

without having to do a duplicated SnippetSerializer like so:

class SnippetSerializerSmall(serializers.HyperlinkedModelSerializer):
    owner = serializers.Field(source='owner.username')

    class Meta:
        model = Snippet
        fields = ('title', 'code')

Upvotes: 2

Views: 873

Answers (1)

Tom Christie
Tom Christie

Reputation: 33921

There's some new documentation on dynamically modifying serializer fields that's just gone up on the site today...

http://django-rest-framework.org/api-guide/serializers.html#dynamically-modifiying-fields

Quoting the docs verbatim here...

Once a serializer has been initialized, the dictionary of fields that are set on the serializer may be accessed using the .fields attribute. Accessing and modifying this attribute allows you to dynamically modify the serializer.

Example

For example, if you wanted to be able to set which fields should be used by a serializer at the point of initializing it, you could create a serializer class like so:

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # Instatiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields:
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields.keys())
            for field_name in existing - allowed:
                self.fields.pop(field_name)

This would then allow you to do the following:

>>> class UserSerializer(DynamicFieldsModelSerializer):
>>>     class Meta:
>>>         model = User
>>>         fields = ('id', 'username', 'email')
>>>
>>> print UserSerializer(user)
{'id': 2, 'username': 'jonwatts', 'email': '[email protected]'}
>>>
>>> print UserSerializer(user, fields=('id', 'email'))
{'id': 2, 'email': '[email protected]'}

Upvotes: 4

Related Questions