annotate 和 aggregate

aggregate() 是 QuerySet 的一个终端子句,使用后将返回“名称-值”的字典
annotate() 不是终端子句。annotate() 子句的输出就是 QuerySet

与aggregate方法不同的是,annotate方法返回结果的不仅仅是含有统计结果的一个字典,而是包含有新增统计字段的查询集(queryset)

假如Student和Hobby是多对多
# 按学生分组,统计每个学生的爱好数量

Student.objects.annotate(Count('hobbies'))   

# 按爱好分组,统计每个爱好的学生数量。

Hobby.objects.annotate(Count('student'))

又例如:

annotate() 和 filter() 子句的顺序
当开发一个涉及 annotate() 和 filter() 子句的复杂查询时,要特别注意应用于 QuerySet 的子句的顺序。

当一个 annotate() 子句应用于查询,会根据查询状态来计算注解,直到请求的注解为止。这实际上意味着 filter() 和 annotate() 不是可交换的操作。

比如:

出版者A有两本评分4和5的书。
出版者B有两本评分1和4的书。
出版者C有一本评分1的书。
下面就是 Count 聚合的例子:

>>> a, b = Publisher.objects.annotate(num_books=Count('book', distinct=True)).filter(book__rating__gt=3.0)
>>> a, a.num_books
(<Publisher: A>, 2)
>>> b, b.num_books
(<Publisher: B>, 2)

>>> a, b = Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count('book'))
>>> a, a.num_books
(<Publisher: A>, 2)
>>> b, b.num_books
(<Publisher: B>, 1)
两个查询返回出版者列表,这些出版者至少有一本评分3的书,因此排除了C。

在第一个查询里,注解优先于过滤器,因此过滤器没有影响注解。distinct=True 用来避免 a query bug。

第二个查询每个发布者评分3以上的书籍数量。过滤器优先于注解,因此过滤器约束计算注解时考虑的对象。


这里是另一个关于 Avg 聚合的例子:

>>> a, b = Publisher.objects.annotate(avg_rating=Avg('book__rating')).filter(book__rating__gt=3.0)
>>> a, a.avg_rating
(<Publisher: A>, 4.5)  # (5+4)/2
>>> b, b.avg_rating
(<Publisher: B>, 2.5)  # (1+4)/2

>>> a, b = Publisher.objects.filter(book__rating__gt=3.0).annotate(avg_rating=Avg('book__rating'))
>>> a, a.avg_rating
(<Publisher: A>, 4.5)  # (5+4)/2
>>> b, b.avg_rating
(<Publisher: B>, 4.0)  # 4/1 (book with rating 1 excluded)
第一个查询请求至少有一本评分3以上的书籍的出版者的书籍平均分。第二个查询只请求评分3以上的作者书籍的平均评分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值