如何在Django ORM单查询中按分组统计多条件数据
单个查询实现按城市统计新增客户与访客数
可以通过Django ORM的Case、When结合Count实现单查询统计,避免两次遍历数据库和结果合并的开销,具体实现如下:
实现代码
首先导入所需的ORM工具:
from django.db.models import Count, Case, When, IntegerField, Q
基础版本(包含所有城市,即使无数据)
# 假设from_date和to_date是已定义的时间段起始、结束日期 statistics = Customer.objects.values("city").order_by("city").annotate( # 统计时间段内新增客户数:仅first_joined在区间内的客户计数 new=Count( Case( When(first_joined__range=(from_date, to_date), then=1), output_field=IntegerField() ) ), # 统计时间段内总访客数:仅last_visited在区间内的客户计数 visitors=Count( Case( When(last_visited__range=(from_date, to_date), then=1), output_field=IntegerField() ) ) )
优化版本(仅保留有新增/访客的城市)
如果不需要显示无数据的城市,可以通过Q对象先过滤出至少满足一个条件的客户,减少查询数据量:
statistics = Customer.objects.filter( Q(first_joined__range=(from_date, to_date)) | Q(last_visited__range=(from_date, to_date)) ).values("city").order_by("city").annotate( new=Count( Case( When(first_joined__range=(from_date, to_date), then=1), output_field=IntegerField() ) ), visitors=Count( Case( When(last_visited__range=(from_date, to_date), then=1), output_field=IntegerField() ) ) )
代码说明
values("city")指定按城市分组annotate中通过Case/When对每个客户进行条件判断:符合时间段条件则返回1,否则返回NoneCount会自动忽略None值,只统计符合条件的客户数量,最终得到每个城市的新增客户数和访客数
输出指定格式
遍历查询结果,输出你需要的表格格式:
print(f"{'city':^6} | {'new':^7} | {'visitors':^9}") print("-" * 30) for item in statistics: print(f"{item['city']:^6} | {item['new']:^7} | {item['visitors']:^9}")
输出效果与你期望的格式一致:
city | new | visitors ------------------------------ A | 12 | 24 B | 34 | 43 C | 9 | 21
内容的提问来源于stack exchange,提问作者Jalaj Kumar
相关产品推荐
相关产品推荐

