Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Append "_id" to foreign key fields in Django Rest Framework

I have a model like so:

class MyModel(models.Model):
    thing = models.ForeignKey('Thing')

Serializers and ViewSet like so:

class ThingSerializer(serializers.ModelSerializer):

    class Meta:
        model = Thing


class MyModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = MyModel

class MyModelViewSet(viewsets.ModelViewSet):

    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer

For MyModel list endpoint, DRF return objects like:

[ 
    { id: 1, thing: 1 },
    { id: 2, thing: 1 },
    { id: 3, thing: 2 },
    { id: 4, thing: 4 }
]

Is there a way to tell DRF to automatically include "_id" on the end of ForeignKey fields that are just IDs and not the actual related object? e.g.

[ 
    { id: 1, thing_id: 1 },
    { id: 2, thing_id: 1 },
    { id: 3, thing_id: 2 },
    { id: 4, thing_id: 4 }
]
like image 882
Matt Avatar asked Jun 18 '16 16:06

Matt


1 Answers

Found same request and solution here:

https://github.com/tomchristie/django-rest-framework/issues/3121

https://gist.github.com/ostcar/eb78515a41ab41d1755b

The AppendIdSerializerMixin.get_fields override suffices for output of JSON objects (with _id appended) but when writing back to the API, it's a little more complicated and the logic in IdPrimaryKeyRelatedField and IdManyRelatedField handles that.

class IdManyRelatedField(relations.ManyRelatedField):
    field_name_suffix = '_ids'

    def bind(self, field_name, parent):
        self.source = field_name[:-len(self.field_name_suffix)]
        super(IdManyRelatedField, self).bind(field_name, parent)


class IdPrimaryKeyRelatedField(relations.PrimaryKeyRelatedField):
    """
    Field that  the field name to FIELD_NAME_id.
    Only works together the our ModelSerializer.
    """
    many_related_field_class = IdManyRelatedField
    field_name_suffix = '_id'

    def bind(self, field_name, parent):
        """
        Called when the field is bound to the serializer.
        Changes the source  so that the original field name is used (removes
        the _id suffix).
        """
        if field_name:
            self.source = field_name[:-len(self.field_name_suffix)]
        super(IdPrimaryKeyRelatedField, self).bind(field_name, parent)


class AppendIdSerializerMixin(object):
    '''
    Append '_id' to FK field names
    https://gist.github.com/ostcar/eb78515a41ab41d1755b
    '''
    serializer_related_field = IdPrimaryKeyRelatedField

    def get_fields(self):
        fields = super(AppendIdSerializerMixin, self).get_fields()
        new_fields = type(fields)()
        for field_name, field in fields.items():
            if getattr(field, 'field_name_suffix', None):
                field_name += field.field_name_suffix
            new_fields[field_name] = field
        return new_fields


class MyModelSerializer(AppendIdSerializerMixin, serializers.ModelSerializer):

    class Meta:
        model = MyModel

class MyModelViewSet(viewsets.ModelViewSet):

    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer
like image 188
Matt Avatar answered Oct 21 '22 10:10

Matt