Models and Databases 3.Aggregati
2021-03-11 本文已影响0人
xncode
两种方式
返回值
Book.objects.all().aggregate(Avg('price'))
Book.objects.aggregate(Avg('price'))
Book.objects.aggregate(price__avg=Avg('price'))
返回
{'price__avg': 34.35}
可同时产生多个值
Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
返回Queryset
Book.objects.annotate(Count('authors'))
Book.objects.annotate(authors__count=Count('authors'))
返回的是Book的Queryset,其中会多一个authors__count字段代表值
由于返回的是Queryset,所有可在结果上进一步操作
注意:如果annotate多个,可能会有问题
Book.objects.annotate(Count('authors'), Count('store'))
使用的是join而不是subquery
一般情况下只能使用两条语句来实现,但是对于count还是可以使用distinct语句
Book.objects.annotate(Count('authors', distinct=True), Count('store', distinct=True))
join
可操作关系字段
和其他查询语句的配合
filter exclude
注意和annotate同时使用的顺序问题,一般情况应该先过滤再使用annotate,否i则在有关系字段时可能发生错误,例如annotate时是按照全部数据进行处理,过滤时只取了一部分,但是已经产生了全部数据的结果
可查看str(queryset.query)
order by
可使用annotate生成的字段进行排序
values
限制返回的列,计算聚合的方式也会不一样,不会再按全部的数据进行聚合,原始的数据会按values指定的字段进行group by,为每一个组进行聚合操作
Author.objects.values('name').annotate(average_rating=Avg('book__rating'))
Author会按照名字进行分组,得出他们各自的书的平均评价分数(注意名字的唯一性,否则会被合并在一起进行计算)
注意排序或默认排序顺序,例如在Meta中的设置
class Item(models.Model):
class Meta:
ordering = ["name"]
即使在values中未出现但是也参与了分组,所以在使用时要去掉排序
Item.objects.values("data").annotate(Count("id")).order_by()
annotation and aggregate
在使用了annotation后也可继续使用aggregate
如果想计算每本书的平均作者数量,先annotate每个书本的作者数量,再aggregate作者
Book.objects.annotate(num_authors=Count('authors')).aggregate(Avg('num_authors'))
{'num_authors__avg': 1.66}
这样会先拿到每个Book的作者数量,拿到一个中间表,在做aggregate的平均值,拿到作者数量的平均值