2018年10月03日
阅读: 4916
Django中聚合函数aggregate()和annotate()的区别
友情提醒:本文最后更新于 2271 天前,文中所描述的信息可能已发生改变,请谨慎使用。
理解Django中聚合函数的关键在于理解SQL中的聚合函数:以下摘自百度百科:SQL基本函数,聚合函数对一组值执行计算,并返回单个值。除了 COUNT 以外,聚合函数都会忽略空值。 常见的聚合函数有AVG / COUNT / MAX / MIN /SUM 等。
一. aggregate的使用方法
aggregate和annotate就是在django中实现聚合函数的。先来看aggregate的使用场景:在项目中有时候你想要从数据库中取出一个汇总的集合。我们使用django官方的例子:
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)
如果我们使用aggregate来进行计数:
# Average price across all books.
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}
# Max price across all books.
>>> from django.db.models import Max
>>> Book.objects.all().aggregate(Max('price'))
{'price__max': Decimal('81.20')}
# Difference between the highest priced book and the average price of all books.
>>> from django.db.models import FloatField
>>> Book.objects.aggregate(
... price_diff=Max('price', output_field=FloatField()) - Avg('price'))
{'price_diff': 46.85}
我们可以看到,aggregate不单单可以求和,还可以求平均Avg,最大最小等等,aggregate的返回值是包含一个key-value的字典(dict)。这里要注意的是如果没有统计到数据,则返回值是None。同时,还可以发现aggregate的逻辑比较简单,应用场景比较窄,如果你想要对数据进行分组(GROUP BY)后再聚合的操作,则需要使用annotate来实现。
二. annotate的使用方法
>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q
<QuerySet [<Book: The Definitive Guide to Django>,<Book: Practical Django Projects>]>
>>> q[0].num_authors
2
>>> q[1].num_authors
1
annotate()为每一个QuerySet在指定属性上生成汇总值,相当于GROUP BY。返回结果类型QuerySet。
另外,Count()还支持传入distinct参数(是否去重),即:
>>> q = Book.objects.annotate(Count('authors'), Count('store'))
>>> q[0].authors__count
6
>>> q[0].store__count
6
# 加参数之后
>>> q = Book.objects.annotate(Count('authors', distinct=True), Count('store', distinct=True))
>>> q[0].authors__count
2
>>> q[0].store__count
3