Search code examples
djangodjango-rest-frameworkdjango-serializer

Seperate a field in the serializer response


This is my serializer and my problem is with the average_rating field. It's repeated in all the instances

class ReviewSerializer(serializers.ModelSerializer):
    average_rating = serializers.SerializerMethodField(read_only=True)
    reviewer = serializers.SerializerMethodField(read_only=True)

    book = serializers.SlugRelatedField(slug_field='title', read_only=True)

    def get_average_rating(self, review):
        book_id = self.context['book_id']
        return Review.objects.filter(book_id=book_id).aggregate(average_rating=Avg('rating'))


    class Meta:
        model = Review
        fields = ["id", "book", "reviewer", "description", 'rating', 'average_rating', ]

what I get is this:

[
    {
        "id": 1,
        "book": "Clean Code: A Handbook of Agile Software Craftsmanship",
        "reviewer": "user1",
        "description": "aaaa",
        "rating": 5,
        "average_rating": {
            "average_rating": 4.5
        }
    },
    {
        "id": 2,
        "book": "Clean Code: A Handbook of Agile Software Craftsmanship",
        "reviewer": "user2",
        "description": "bbbb",
        "rating": 5,
        "average_rating": {
            "average_rating": 4.5
        }
    },
]

but I need this: I don't want average_rating to repeat for all instances and make extra queries. what can I do here?

[
 "average_rating": {
            "average_rating": 4.5
        },
    {
        "id": 1,
        "book": "Clean Code: A Handbook of Agile Software Craftsmanship",
        "reviewer": "user1",
        "description": "aaaa",
        "rating": 5,
    },
    {
        "id": 2,
        "book": "Clean Code: A Handbook of Agile Software Craftsmanship",
        "reviewer": "user2",
        "description": "bbbb",
        "rating": 5,
    },
]

Solution

  • Since you are using SerializerMethodField the particular query will run with each object which is not a best practice.

    You can run the query once in views and return it with response.

    avg = Review.objects.aggregate(average_rating=Avg('rating'))
    serializer = ReviewSerializer(query, many=True)
    return Response({'average_rating':avg['average_rating'], 'item':serializer.data})