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

如何在Django ORM中使用Group by子句且不包含模型ID?

问题描述

模型定义:

class Model1(models.Model):
    category = models.CharField()
    name = models.CharField()

想要统计每个category的数量,编写了如下ORM语句:

from django.db.models import Count

result = Model1.objects.values('category').annotate(Count('sns_type'))

得到的查询结果:

<QuerySet [{'category': 'A', 'category__count': 1}, 
{'category': 'B', 'category__count': 1},...]>

打印对应的SQL语句,发现自动包含了id的分组:

SELECT "example_table"."category", COUNT("example_table"."category") AS "category__count" 
FROM "example_table" 
GROUP BY "example_table"."category", "example_table"."id"

期望的SQL语句应该是:

SELECT "example_table"."category", COUNT("example_table"."category") AS "category__count" 
FROM "example_table" 
GROUP BY "example_table"."category"

需要实现不包含模型ID的GROUP BY分组。


解决方法

原因分析

Django的QuerySet默认会添加基于模型主键(id)的排序规则,而SQL标准要求GROUP BY子句必须包含所有非聚合的SELECT字段以及排序字段,因此id会被自动加入GROUP BY中。另外你的ORM语句里Count('sns_type')存在错误——模型中并没有sns_type字段,Django会自动 fallback 到统计主键id,这也间接加剧了这个问题。

修正后的ORM写法

  1. 修正聚合字段:将Count('sns_type')改为正确的字段,比如统计主键使用Count('id'),或者统计category本身用Count('category'),也可以用Count('*')统计分组内的总条数。
  2. 清空默认排序:在QuerySet末尾添加.order_by(),去掉Django自动添加的主键排序规则,这样GROUP BY就只会包含你指定的category字段。

最终代码:

from django.db.models import Count

# 统计每个category的数量,GROUP BY仅包含category
result = Model1.objects.values('category').annotate(count=Count('id')).order_by()

对应的SQL语句会变成你期望的样子:

SELECT "example_table"."category", COUNT("example_table"."id") AS "count" 
FROM "example_table" 
GROUP BY "example_table"."category"

额外说明

如果使用的是Django 3.2及以上版本,也可以通过修改模型的Meta类中的ordering属性,去掉默认的主键排序,但这种方式会影响整个模型的所有QuerySet,不如在单个查询中使用.order_by()更灵活。

内容的提问来源于stack exchange,提问作者Universpace

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 01:18:14