Django - How can you include annotated results in a serialized QuerySet?
Asked Answered
D

4

13

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!

Dildo answered 20/8, 2014 at 9:21 Comment(0)
N
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)
Nevertheless answered 21/8, 2014 at 7:13 Comment(0)
S
10

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)

Shavonda answered 31/3, 2020 at 8:14 Comment(4)
this should be the accepted answer it works perfectly!Dialyse
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.Taught
There is no ModelSerializer class in Django.Caiman
I meant drf's ModelSerializer django-rest-framework.org/api-guide/serializers/…Shavonda
B
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.

Bioastronautics answered 20/8, 2014 at 9:39 Comment(2)
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?Dildo
As of October 2017, the pull request has been closed without being merged, and the ticket is still open.Telic
X
-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}]
Xenomorphic answered 20/8, 2014 at 9:33 Comment(1)
The count that i make is correct, the problem is the serializer class. But thanks for the help!Dildo

© 2022 - 2025 — McMap. All rights reserved.