
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