Dustin Wyatt
Dustin Wyatt

Reputation: 4244

How to exclude parent when serializer is nested when using Django REST Framework?

I feel like this is probably in the docs but I just can't seem to figure it out.

If I've got a serializer with a ForeignKey included in its fields how do I exclude that FK when that serializer is nested in the related object?

class EmployerSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Employer
        fields = ('name', 'person')

class PersonSerializer(serializers.HyperlinkedModelSerializer):
    employers = EmployerSerializer()

    class Meta:
        model = Person
        fields = ('name', 'employers')
        depth = 1

When I hit the API at http://0.0.0.0:8000/person/1/ it lists something like:

{
    "name": "Joe Blow",
    "employers": {
        "name": "Acme Inc."
        "person": "http://0.0.0.0:8000/person/1/"
        }
}

The "person" key for "employers" is self-referential and redundant, but only when the serializer is nested within the object it's referring to.

It seems like there should be an option to exclude it when the serializer is nested, but I can't figure it out.

Upvotes: 1

Views: 2631

Answers (1)

Venkatesh Bachu
Venkatesh Bachu

Reputation: 2553

class DynamicFieldsModelSerializer(serializers.HyperlinkedModelSerializer):
    """
    A HyperlinkedModelSerializer 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)
        exclude = kwargs.pop('exclude', None)
        # Instantiate 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)
        if exclude:
            # Drop fields that are specified in the `exclude` argument.
            excluded = set(exclude)
            for field_name in excluded:
                try:
                    self.fields.pop(field_name)
                except KeyError:
                    pass

extend EmployerSerializer with DynamicFieldsModelSerializer

class EmployerSerializer(DynamicFieldsModelSerializer):
    class Meta:
       model = Employer
       fields = ('name', 'person')


class PersonSerializer(serializers.HyperlinkedModelSerializer):
    employers = EmployerSerializer(exclude=('name',))
    class Meta:
        model = Person
        fields = ('name', 'employers')
        depth = 1

Upvotes: 7

Related Questions