48

我正在为 QuerySet 中的每个项目生成聚合:

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

但我没有得到 JSON 响应中的计数。

先感谢您。

4

4 回答 4

87

接受的解决方案将在返回结果时多次访问数据库。对于每个结果,count将对数据库进行查询。

count问题是关于向序列化程序添加注释,这比对响应中的每个项目进行查询更有效。

一个解决方案:

模型.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...
    ...

序列化程序.py

class BookSerializer(serializers.ModelSerializer):
    authors = serializers.IntegerField()

    class Meta:
        model = Book
        fields = ('id', 'title', 'authors')

视图.py

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

这将在数​​据库级别进行计数,避免访问数据库以检索每个返回Book项目的作者计数。

于 2016-04-18T14:57:09.693 回答
37

从 get_queryset 返回的查询集提供将通过序列化程序的事物列表,序列化程序控制对象的表示方式。尝试在您的 Book 序列化程序中添加一个附加字段,例如:

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

编辑:正如其他人所说,这不是为返回许多结果的情况添加计数的最有效方法,因为它会针对每个实例访问数据库。请参阅@José 的答案以获得更有效的解决方案。

于 2013-08-26T01:22:42.780 回答
7

Fiver 的解决方案将为查询集中的每个实例命中数据库,因此如果您有一个大型查询集,他的解决方案将创建大量查询。

我会覆盖您的 Book 序列化程序的to_representation ,它会重用annotation的结果。它看起来像:

class BookSerializer(serializers.ModelSerializer):
     def to_representation(self, instance):
        return {'id': instance.pk, 'num_authors': instance.authors__count}

    class Meta:
        model = Book
于 2015-07-11T07:52:42.277 回答
0

所以,如果你做一个像这样的注释

Model.objects.annotate(
    some_new_col=Case(
        When(some_field=some_value, then=Value(something)),
        # etc...
        default=Value(something_default),
        output_field=SomeTypeOfField(),
    )
).filter()#etccc

并且解释器抛出一个something不是相关模型字段的错误serializer,有一个解决方法。这不好,但如果你添加一个方法some_new_col,它会识别上面查询中的值。以下将做得很好。

def some_new_col(self):
    pass;
于 2021-02-02T10:21:08.767 回答