聚合函数和排序函数
这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战
在本指南(以及参考资料)中,我们将参考以下模型,
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
class Publisher(models.Model):
name = models.CharField(max_length=300)
class Book(models.Model):
name = models.CharField(max_length=300)
pages = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
rating = models.FloatField()
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
pubdate = models.DateField()
class Store(models.Model):
name = models.CharField(max_length=300)
books = models.ManyToManyField(Book)
1. 聚合函数
aggregate()
使用aggregate()过滤器调用聚合函数。聚合函数包括:Avg平均,Count数量,Max最大,Min最小,Sum求和,被定义在django.db.models中。
下面是根据以上模型执行常见的聚合查询:
>>> Book.objects.count()
>>> Book.objects.filter(publisher__name='BaloneyPress').count()
>>> Book.objects.all().aggregate(Avg('price'))
>>> Book.objects.all().aggregate(Max('price'))
>>> Book.objects.aggregate(
... price_diff=Max('price', output_field=FloatField()) - Avg('price'))
>>> pubs = Publisher.objects.annotate(num_books=Count('book'))
>>> above_5 = Count('book', filter=Q(book__rating__gt=5))
>>> below_5 = Count('book', filter=Q(book__rating__lte=5))
注意count函数的返回值是一个数字。
在 QuerySet 上生成聚合
Django 提供了两种生成聚合的方法。第一种方法是从整个 QuerySet 生成汇总值。比如你想要计算所有在售书的平均价格。Django 的查询语法提供了一种用来描述所有图书集合的方法:
>>> Book.objects.all()
- 可以通过在
QuerySet后添加aggregate()子句来计算QuerySet对象的汇总值。
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}
- 本例中的
all()是多余的,所以可以简化成这样的:
>>> Book.objects.aggregate(Avg('price'))
{'price__avg': 34.35}
传递给 aggregate() 的参数描述了我们想要计算的聚合值。在这个例子里,要计算的就是 Book 模型上的 price 字段的平均值。可用的聚合函数列表可以在 QuerySet reference 中找到。
annotate()
为 QuerySet 中的每一个条目生成聚合
与 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()` 进行额外调用。
2. 排序
使用order_by对结果进行排序
order_by()
order_by可以当做基本排序来使用。当你定义了一个 order_by() 子句,你提供的聚合可以引用任何定义为查询中 annotate() 子句的一部分的别名。
比如,通过书籍的作者数量来对书籍的 QuerySet 排序,你可以使用下面的查询:
>>> Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')
与默认排序或 order_by() 交互
2.2 版后已移除:从Django 3.1 中开始,模型的 Meta.ordering 中的排序不会使用在 GROUP BY 查询,比如 .annotate().values() 。从 Django 2.2 开始,这些查询发出一个弃用警告,指示要在查询集中添加一个显式的 order_by() 来静默警告。