Django聚合函数与aggregate、annotate方法详解

Owen
Owen
发布时间:2026-10-13 | 5人浏览过
原创

本文详解Django中Avg、Count等聚合函数的用法,深入对比aggregate与annotate两种支持聚合的方法。通过实例解析aggregate如何对QuerySet整体汇总,以及annotate如何为每个对象生成独立摘要并自动分组,帮助开发者掌握Django数据聚合的核心技巧。

Django聚合函数支持方法概览

支持聚合函数的方法:

在Django中使用聚合函数时,不能直接调用,必须将其嵌入到支持聚合的方法中执行。主要支持聚合的方法有两种:aggregate和annotate。这两种方法生成的原生SQL语句及返回结果存在显著差异,下文将通过具体实例逐一说明。


  # 示例模型:
  class Author(models.Model):
    """作者模型"""
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    email = models.EmailField() 

  class Book(models.Model):
    """图书模型"""
    name = models.CharField(max_length=100)
    author = models.ForeignKey('Author',on_delete=models.CASCADE)
    price = models.FloatField()

  class BookOrder(models.Model):
    """图书订单模型"""
    book = models.ForeignKey('Book',on_delete=models.CASCADE)
    sailprice = models.FloatField()
    create_time = models.DateTimeField(auto_now_add=True)

aggregate方法详解与示例

1、aggregate:作为QuerySet对象的API,该方法对QuerySet整体进行属性汇总,不基于模型主键进行group by分组,最终返回一个结果字典。此外,aggregate支持聚合关联表(如ForeignKey关联)中的字段,传递关联字段的方式与常规连表查询一致,需使用“__”符号。示例代码如下:


  from django.db.models import Avg
  from django.db import connection

1、对当前表中数据进行聚合:


  result = Author.objects.aggregate(avg_age=Avg('age'))
  print(connection.queries)	  # 打印执行时所有的查询语句

2、对连表中数据进行聚合:


  result = Book.objects.aggregate(sum=Sum('bookorder__price'))

annotate方法详解与示例

2、annotate:此方法不仅支持执行聚合函数,还可传递F或Q对象,为当前QuerySet生成新的属性。

annotate通常用于聚合连表字段,它为QuerySet中的每个对象生成独立的摘要,并为查询模型增加一个新属性,其值为聚合函数的结果。使用aggregate函数生成新字段时,annotate会基于模型主键进行group by分组(注意:仅在使用聚合函数生成新字段时进行分组,使用F、Q表达式添加新字段时不分组),随后在连表中按分组结果进行聚合。这符合为QuerySet中每个对象增加独立摘要的特性。

使用该方法执行聚合函数后,返回结果仍为QuerySet对象,可继续调用filter()、order_by()甚至再次使用annotate()进行聚合。例如,提取每本书的平均销售价格(价格数据位于BookOrder表):


  from django.db.models import Avg
  from django.db import connection 

  books = Book.objects.annotate(avg=Avg('bookorder__sailprice'))
  for book in books:
  print('%s/%s'%(book.name,book.avg))  	# 注意这里的avg属性就是annotate执行聚合函数得到的
  print(connection.queries)

常用聚合函数介绍

聚合函数:

Django中的聚合函数均位于django.db.models模块下,具体包括Avg、Count、Max、Min和Sum。以下逐一介绍各函数的作用:

1、Avg:计算平均值,适用于数值型字段。若使用aggregate执行此函数,将返回一个字典,默认键名为field__avg,值为聚合结果。示例代码如下:


  # 计算所有作者的平均年龄
  result = Author.objects.aggregate(Avg('age'))
  print(result)	# 结果为:{"age__avg": 23.8}

  # 如果想要使用自定义的键,那么可以把aggregate中的未知参数变为关键字参数,该关键字就是得到的键,示例代码如下:
  result = Author.objects.aggregate(avgAge=Avg('age'))
  print(result)	# 结果为:{"avgAge": 23.8} 

  # 如果使用annotate方法执行这个函数,那么得到的结果就是一个QuerySet对象,只不过这个对象中的每一个都会添加一个属性,这个属性的名称其实和上面的键一样,可以使用默认也可以自定义,使用方法与在aggregate中键名的定义一样,这里就不再赘述:	
  books = Book.objects.annotate(avg=Avg('bookorder__sailprice'))
  for book in books:
    print('%s/%s'%(book.name,book.avg))	# 注意这里的avg属性就是annotate执行聚合函数得到的
  print(connection.queries)

2、Count:计算数量,基本用法与Avg类似。使用该函数时可传入distinct参数以实现去重:


  # 计算总共有多少个订单
  result = BookOrder.objects.aggregate(total=Count('id',distanct=True))
  print(result)	# 结果为:{"total": 18}
 
  # 计算每本书的订单量
  books = Book.objects.annotate(total=Count('bookorder__id'))
  for book in books:
  print('%s/%s'%(book.name,book.total))

3、Max和Min:计算字段的最大值和最小值,用法与Avg相同。

4、Sum:计算总和,用法与Avg相同。

注:总结而言,aggregate是对QuerySet整体属性的汇总聚合,不执行分组;而annotate是为QuerySet中每个对象生成独立摘要,必然执行分组后再进行聚合。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表