Django QuerySet如何基于Avg聚合条件按月统计A模型实例数量
问题原因
原有ORM代码存在两个核心错误:
- 语法错误:
amountfield__avg是聚合运算后缀,不能直接写在Q()对象中作为过滤条件,只有提前通过annotate定义聚合字段后,才能在过滤逻辑里引用聚合结果 - 逻辑错误:直接按月份单维度分组,会把同一个月下所有不同A实例关联的B记录混在一起计算,无法单独判断每个A实例的关联B平均值是否为0,分组维度不符合需求
额外注意:直接取datetimefield__month会把不同年份的同月份数据合并(比如2023年1月和2024年1月会被算成同一个月),统计结果不符合绝大多数按月统计的业务要求,建议用TruncMonth做时间截断保留年月维度。
正确实现代码
首先导入需要的依赖:
from django.db.models import Avg, Count from django.db.models.functions import TruncMonth
分两次分组实现统计需求:
stat_result = ( B.objects # 截断时间到年月维度 .annotate(month=TruncMonth("datetimefield")) # 第一级分组:按 月份 + 关联的A实例 分组,计算每个A在对应月份的amount平均值 .values("month", "a_field") .annotate(avg_amount=Avg("amountfield")) # 过滤出平均值为0的A+月份组合 .filter(avg_amount=0) # 第二级分组:按月份分组,统计每个月符合条件的A实例数量 .values("month") .annotate(valid_a_count=Count("a_field", distinct=True)) .order_by("month") )
结果说明
返回的查询集中每个元素包含两个字段:
month:对应统计的年月(datetime类型,比如2024-01-01表示2024年1月)valid_a_count:该月份下,关联B记录的amountfield平均值为0的A实例数量
如果你确实不需要区分年份,只需要按1-12的自然月统计,可以把TruncMonth("datetimefield")替换为datetimefield__month,后续分组字段对应改成datetimefield__month即可。
内容的提问来源于stack exchange,提问作者leauradmin
相关产品推荐
相关产品推荐

