You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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,否则返回None
  • Count 会自动忽略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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 03:35:03