Django4.0 聚合-在QuerySet中的每一个条目生成聚合
生成值的汇总的另一个办法是为 QuerySet
的每一个对象生成独立汇总。比如,如果你想检索书籍列表,你可能想知道每一本书有多少作者。每一本书与作者有多对多的关系;我们想在 QuerySet
中为每一本书总结这个关系。
使用 annotate()
子句可以生成每一个对象的汇总。当指定 annotate()
子句,QuerySet
中的每一个对象将对指定值进行汇总。
这些语法与用于 aggregate()
子句的语法相同。 annotate() 的每个参数都描述了一个要计算的聚合。 例如,用作者数量注释书籍:
# Build an annotated queryset
>>> from django.db.models import Count
>>> q = Book.objects.annotate(Count('authors'))
# Interrogate the first object in the queryset
>>> q[0]
<Book: The Definitive Guide to Django>
>>> q[0].authors__count
2
# Interrogate the second object in the queryset
>>> q[1]
<Book: Practical Django Projects>
>>> q[1].authors__count
1
与 aggregate()
一样,注解的名称是根据聚合函数和被聚合的字段名自动生成的。当你在指定注解的时候,你可以通过提供一个别名重写这个默认名:
>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1
与 aggregate()
不同的是,annotate()
不是终端子句。annotate()
子句的输出就是 QuerySet
;这个 QuerySet
被其他 QuerySet
操作进行修改,包括 filter()
, order_by()
,甚至可以对 annotate()
进行额外调用。
组合多个聚合
将多个聚合与 annotate()
组合会产生错误的结果,因为使用的是连接而不是子查询:
>>> book = Book.objects.first()
>>> book.authors.count()
2
>>> book.store_set.count()
3
>>> q = Book.objects.annotate(Count('authors'), Count('store'))
>>> q[0].authors__count
6
>>> q[0].store__count
6
对大部分聚合来说,没办法避免这个问题,但是,Count
聚合可以使用 distinct
参数来避免:
>>> q = Book.objects.annotate(Count('authors', distinct=True), Count('store', distinct=True))
>>> q[0].authors__count
2
>>> q[0].store__count
3