Django4 中文入门教程 Django4.0 聚合-连接(Joins)和聚合

2024-02-25 开发教程 Django4 中文入门教程 匿名 7

到目前为止,我们已经处理了被查询模型字段的聚合。然而,有时候想聚合的值属于你正在查询模型的关联模型。

当在聚合函数中指定要聚合的字段时,Django 将允许您使用与在过滤器中引用相关字段时使用的相同的双下划线表示法。 然后,Django 将处理检索和聚合相关值所需的任何表连接。

比如,要寻找每个书店提供的书籍价格区间,你可以使用这个注解(annotation):

>>> from django.db.models import Max, Min
>>> Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price'))

这告诉 Django 去检索 ​Store ​模型,连接(通过多对多关系) ​Book ​模型,并且聚合书籍模型的价格字段来获取最大最小值。
相同规则应用于 ​aggregate()​ 从句。如果你想知道任何店铺正在销售的任何书籍的最低最高价,你可以使用这个聚合:

>>> Store.objects.aggregate(min_price=Min('books__price'), max_price=Max('books__price'))

Join ​链可以根据你的需求尽可能深。比如,要提取所出售的书籍中最年轻的作者年龄,你可以写这样的查询:

>>> Store.objects.aggregate(youngest_age=Min('books__authors__age'))

反向关系

以类似于跨越关系的查找的方式,在与您查询的模型或模型相关的字段上的聚合和注释可以包括遍历反向关系。 此处也使用相关模型的小写名称和双下划线。

例如,我们可以查询所有出版商,并用他们各自的总图书库存计数器进行注释(注意我们如何使用 'book' 来指定 Publisher -> Book 反向外键跳转):

>>> from django.db.models import Avg, Count, Min, Sum
>>> Publisher.objects.annotate(Count('book'))

(查询结果里的每一个 Publisher 会有多余的属性—— book__count 。)
我们也可以找出最古老的一本:

>>> Publisher.objects.aggregate(oldest_pubdate=Min('book__pubdate'))

(结果字典中会有一个叫 'oldest_pubdate' 的键。如果没有指定这样的别名,它将会是一个很长的名字 'book__pubdate__min' 。)
它不仅仅用于外键,它也适用于多对多关系。比如,我们能查询每一个作者,作者(共同)创作的书籍总页数(注意我们如何使用 'book' 来指定 Author -> Book 反向多对多跳转):

>>> Author.objects.annotate(total_pages=Sum('book__pages'))

(结果集里的每一个 Author 会有一个额外的属性——total_pages)如果没有指定这样的别名,它将会是一个很长的名字 book__pages__sum)
或查询书籍的平均评分:

>>> Author.objects.aggregate(average_rating=Avg('book__rating'))

(结果字典里会有一个叫 'average_rating' 的键。如果没有指定这样的别名,它将会是一个很长的名字 'book__rating__avg'。)