14

How can you include annotated results in a serialized QuerySet?

data = serializer.serialize(Books.objects.filter(publisher__id=id).annotate(num_books=Count('related_books')), use_natural_keys=True)

However the key/value pare {'num_books': number} is not include into the json result.

I've been searching for similar questions on the internet, but i didn't found a solution that worked for me.

Here is a similar case: http://python.6.x6.nabble.com/How-can-you-include-annotated-results-in-a-serialized-QuerySet-td67238.html

Thanks!

4 Answers 4

13

I did some research and found that serializer.serialize can only serialize queryset, and annotation just adds an attribute with each object of the queryset, so when you try to serialize a query, annotated fields aren't shown. This is my way of implementation:

from django.core.serializers.json import DjangoJSONEncoder

books = Books.objects.filter(publisher__id=id).annotate(num_books=Count('related_books')).values()
json_data = json.dumps(list(books), cls=DjangoJSONEncoder)
Sign up to request clarification or add additional context in comments.

Comments

11

As shown in this post you can use SerializerMethodField in your Serializer:

class BooksSerializer(serializers.ModelSerializer):

  num_books = serializers.SerializerMethodField()

  def get_num_books(self, obj):
    try:
        return obj.num_books
    except:
        return None

It will serialize the annotated value (readonly)

4 Comments

this should be the accepted answer it works perfectly!
This is the correct answer. AIt is also possible to do the same annotation logic in the serializers.SerializerMethodField() method, however not preferable if already done on queryset to avoid duplicating code.
There is no ModelSerializer class in Django.
1

Based on the link, this has been solved by pull request (https://github.com/django/django/pull/1176) some months ago.

You need to add num_books as a property:

class Publisher():
    ....

    @property
    def num_books(self):
        return some_way_to_count('related_books')

and then call it like so:

data = serializer.serialize(Books.objects.filter(publisher__id=id)), use_natural_keys=True, extra=['num_books'])

I'm not too sure about the exact syntax, since I don't work much with serializers.

2 Comments

Thanks for the help, but i can't make it work. Also, if my Model is the Django built in User (from django.contrib.auth.models import User) how do you do it?
As of October 2017, the pull request has been closed without being merged, and the ticket is still open.
-1

To get count from specific columns, you must declare them via values method

>>>> Books.objects.filter(publisher__id=id).values('<group by field>').annotate(num_books=Count('related_books'))
[{'num_books': 1, '<group by field>': X}]

1 Comment

The count that i make is correct, the problem is the serializer class. But thanks for the help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.