nicwhitts nicwhitts - 3 months ago 15
Python Question

Filtering serializer response data

I have a ManyToMany relation with tag and items:

class Tag(BaseModel):
name = models.CharField(max_length=255) # ToDo Change max length
description = models.TextField(blank=True, null=True)


class Item(BaseModel):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
image = models.ImageField(upload_to='items', blank=True)
title = models.TextField(blank=False, null=True)
message = models.TextField(blank=True, null=True)
fav_count = models.IntegerField(default=0)
tags = models.ManyToManyField(Tag, related_name='tags')


I need all fields to be serialized, but i wish to only limit the response values.
Example:

What I'm receiving now:

{
"user": 2,
"image": null,
"title": "test3",
"message": "testmessage",
"fav_count": 0,
"tags": [
{
"id": 7,
"name": "tag1",
"description": null
},
{
"id": 8,
"name": "tag2",
"description": null
}
]
}


But i only wish to receive the tag ids not the name and description...

My simple view:

if request.method == 'GET':
items = Item.objects.all()
serializer = ItemSerializer(items, many=True)
return Response(serializer.data)


Would i need to rebuild my response data to include/exclude or is there a better way to do this? (or if iv missed the terminology)

Answer

use PrimaryKeyRelatedField DRF field in your serializer

Example

class ItemSerializer(serializers.ModelSerializer):
    tags = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Item
        fields = ('tags', 'image',.....other fields)

Response

{
    'image': 'image1',
    ...........
    'tags': [
        89,
        90,
        91,
        ...
    ]
    ..........
}

In you want to do it dynamically based on a request parameter.

   class ItemSerializer(serializers.ModelSerializer):
        tags = serializers.SerializerMethodField()

   def get_tags(self, obj):
       if self.request.get('some_condition'):
           data_tags = TagSerializer(obj.tags, many=True).data
           data = map(data.pop('field_to_remove') for data in data_tags)
           return list(data)
       else:
           return TagSerializer(obj.tags, many=True).data

Then, pass request to your serializer when you init it in your view.

serializer = ItemSerializer(data, context={'request':self.request})