Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to add annotate data in django-rest-framework queryset responses?

I am generating aggregates for each item in a QuerySet:

def get_queryset(self):     from django.db.models import Count     queryset = Book.objects.annotate(Count('authors'))     return queryset 

But I am not getting the count in the JSON response.

thank you in advance.

like image 450
panchicore Avatar asked Aug 25 '13 22:08

panchicore


Video Answer


2 Answers

The accepted solution will hit the database as many times as results are returned. For each result, a count query to the database will be made.

The question is about adding annotations to the serializer, which is way more effective than doing a count query for each item in the response.

A solution for that:

models.py

class Author(models.Model):     name = models.CharField(...)     other_stuff = models...     ...  class Book(models.Model):     author = models.ForeignKey(Author)     title = models.CharField(...)     publication_year = models...     ... 

serializers.py

class BookSerializer(serializers.ModelSerializer):     authors = serializers.IntegerField()      class Meta:         model = Book         fields = ('id', 'title', 'authors') 

views.py

class BookViewSet(viewsets.ModelViewSet):     queryset = Book.objects.annotate(authors=Count('author'))     serializer_class = BookSerializer     ... 

That will make the counting at database level, avoiding to hit database to retrieve authors count for each one of the returned Book items.

like image 191
José L. Patiño Avatar answered Sep 22 '22 22:09

José L. Patiño


The queryset returned from get_queryset provides the list of things that will go through the serializer, which controls how the objects will be represented. Try adding an additional field in your Book serializer, like:

author_count = serializers.IntegerField(     source='author_set.count',      read_only=True ) 

Edit: As others have stated, this is not the most efficient way to add counts for cases where many results are returned, as it will hit the database for each instance. See the answer by @José for a more efficient solution.

like image 28
Fiver Avatar answered Sep 24 '22 22:09

Fiver