Django单查询内按多字段条件统计QuerySet对象数量的更优实现
优化方案
你的原有实现可以进一步简化和提效,最优方案是直接在aggregate聚合函数中使用带filter参数的Count,省略中间annotate行级注解再求和的步骤,既满足单次查询完成所有统计的要求,也降低了数据库执行开销,代码更易维护。
基础实现(适合统计项较少的场景)
from django.db.models import Count, Q car_stats = Car.objects.aggregate( # 统计John的黑色Saloon数量 black_saloons_owned_by_john=Count( "id", filter=Q(type=2, color="black", owner__first_name="John") ), # 统计Matt的白色Hatchback数量 white_hatchbacks_owned_by_matt=Count( "id", filter=Q(type=1, color="white", owner__first_name="Matt") ), # 其他统计项直接在此处追加即可 )
注:你原有代码中的统计条件遗漏了
color字段过滤,上述示例补全了对应需求的条件。
动态实现(适合统计项较多的场景)
如果统计规则数量多,可以把统计规则统一维护在字典中,动态生成聚合参数,不需要硬写每个统计字段,后续新增/修改统计规则只需要调整字典即可:
from django.db.models import Count, Q # 统一定义所有统计规则:key为返回结果的字段名,value为对应过滤条件 count_rules = { "black_saloons_owned_by_john": Q(type=2, color="black", owner__first_name="John"), "white_hatchbacks_owned_by_matt": Q(type=1, color="white", owner__first_name="Matt"), "red_saloons_owned_by_lily": Q(type=2, color="red", owner__first_name="Lily"), # 新增统计项仅需在此处加条目 } # 动态构造聚合参数 aggregate_params = { field_name: Count("id", filter=q_condition) for field_name, q_condition in count_rules.items() } car_stats = Car.objects.aggregate(**aggregate_params)
方案优势
- 性能更优:省去了行级注解的中间步骤,数据库执行的SQL更简洁,数据量越大性能提升越明显
- 维护成本更低:统计规则集中管理,不需要修改查询逻辑即可调整统计项
- 完全满足单次查询的要求,所有统计逻辑合并为一条SQL执行,不会产生额外数据库请求
内容的提问来源于stack exchange,提问作者Alexandr Shaulskyi
相关产品推荐
相关产品推荐

