不使用Raw SQL,如何用Django Query合并两张分组统计结果表
解决方案:合并Django分组统计结果并显示双列计数
方案一:单查询实现双条件计数(推荐)
直接在数据库层面完成统计,用Case和When区分不同条件的计数,一次查询搞定,效率最高:
from django.db.models import Count, Case, When, IntegerField # 统计每个name在两个条件下的计数,无数据则显示0 result = Entity.objects.filter(some_condition__in=[1, 2]) .values("name") .annotate( count_condition1=Count(Case( When(some_condition=1, then=1), output_field=IntegerField() )), count_condition2=Count(Case( When(some_condition=2, then=1), output_field=IntegerField() )) )
返回的每条结果包含name、count_condition1(对应原q1的计数)、count_condition2(对应原q2的计数)三个字段,自动处理无数据的情况为0。如果要包含所有name(哪怕两个条件下都没数据),删掉filter(some_condition__in=[1, 2])即可。
方案二:内存合并已有查询集
如果已经生成了q1和q2,可转成字典后合并:
# 将查询集转为{name: 计数}的字典 dict_q1 = {item["name"]: item["name__count"] for item in q1} dict_q2 = {item["name"]: item["name__count"] for item in q2} # 提取所有出现过的name all_names = set(dict_q1.keys()).union(set(dict_q2.keys())) # 生成合并后的结果列表 merged_result = [ { "name": name, "count_condition1": dict_q1.get(name, 0), "count_condition2": dict_q2.get(name, 0) } for name in all_names ]
这种方式会触发两次数据库查询,适合数据量较小的场景。
为什么之前的方法失效?
q1 | q2会把两个查询的结果合并,Django会自动将同name的计数合并到同一列,无法区分是哪个条件的统计结果。union要求两个查询集的字段完全一致,且annotate生成的查询默认带排序,而SQL的复合查询不允许子查询包含ORDER BY,所以报错。
内容的提问来源于stack exchange,提问作者plategt
相关产品推荐
相关产品推荐

