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的平均值,拿到作者数量的平均值

上一篇下一篇

猜你喜欢

热点阅读