Django中聚合函数aggregate()和annotate()的区别

友情提醒:本文最后更新于 2024 天前,文中所描述的信息可能已发生改变,请谨慎使用。

      理解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

上一篇:Django QuerySet查询优化

下一篇:apache ab压力测试工具参数及返回结果释义