Django中的aggregate()和annotate()比较

193 投票
4 回答
67313 浏览
提问于 2025-04-17 05:29

Django中的QuerySet有两个方法,分别是annotateaggregate。文档中提到:

aggregate()不同,annotate()不是一个终止的操作。使用annotate()后,输出仍然是一个QuerySet。

它们之间还有其他区别吗?如果没有,那aggregate存在的意义是什么呢?

4 个回答

23

这就是主要的区别,但聚合在处理上比注解更大规模。注解本质上是和查询集中每个单独的项目相关的。如果你在一个像多对多字段的东西上运行一个Count注解,你会得到查询集中每个成员的单独计数(作为一个额外的属性)。然而,如果你用聚合做同样的事情,它会尝试计算查询集中每个成员的每个关系,甚至包括重复的关系,然后只返回一个值。

43

聚合(Aggregate)
聚合是对整个查询结果集进行处理,生成一些总结性的值。简单来说,它会从一组数据中提取出一个单一的值,比如说计算所有价格的总和。聚合是针对整个查询结果集进行的,最终会得到一个总结性的结果。

在模型中:

class Books(models.Model):
    name = models.CharField(max_length=100)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=5, decimal_places=3)

在命令行中:

>>> Books.objects.all().aggregate(Avg('price'))
# Above code will give the Average of the price Column 
>>> {'price__avg': 34.35}

注解(Annotate)
注解则是为查询结果集中的每一个对象生成独立的总结。可以理解为它会逐个遍历查询结果集中的每个对象,并对其进行操作。

在模型中:

class Video(models.Model):
    name = models.CharField(max_length=52, verbose_name='Name')
    video = models.FileField(upload_to=document_path, verbose_name='Upload 
               video')
    created_by = models.ForeignKey(User, verbose_name='Created by', 
                       related_name="create_%(class)s")
    user_likes = models.ManyToManyField(UserProfile, null=True, 
                  blank=True, help_text='User can like once', 
                         verbose_name='Like by')

在视图中:

videos = Video.objects.values('id', 'name','video').annotate(Count('user_likes',distinct=True)

在视图中,它会统计每个视频的点赞数

292

我建议你关注示例查询,而不是文档中的引用。Aggregate 是用来计算整个查询结果的值,而 Annotate 则是用来计算查询结果中每一项的总结值。

聚合

>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}

这个代码会返回一个字典,里面包含了查询结果中所有书籍的平均价格。

注解

>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1

q 是书籍的查询结果,但每本书都被注解了作者的数量。

撰写回答