关于 annotate 运行与预想不符(group by 多一个字段)的问题

解决

由于在 model 中的 meta 添加了默认的 order_by,导致使用 annotate 时一直无法满足预期的结果,只需要添加空的 order_by 重置排序,或者删去默认排序即可。

过程

在 django 中,使用 anotate 来做分组查询。以下是对 annotate 的介绍以及为什么我会出现问题的描述。

假设我们有这么一张表 table1:

id 用户名 username 系统 system
1 张三 Windows
2 李四 Android
3 王五 IOS
4 赵六 Windows

如果我们要对统计有多少人在使用使用这些系统,只需要这么一小句 SQL 语句

select system, count(device) from table1 group by system;

输出如下:

+---------+---------------+
| device  | count(device) |
+---------+---------------+
| Android |             1 |
| IOS     |             1 |
| Windows |             2 |
+---------+---------------+

而在 django 中理论上只需要这样即可完成上述操作(假设 Table1 为模型类):

from django.db.models import Count

queryset = Table1.objects.values("device").annotate(Count("device"))

然而事实并不如我所愿,在语句执行之后,发现目标字段并没有进行分组,而是单独分开成了一个组,结果大概就像下面这样,所以 Count(“device”) 就变成了 1。

+---------+---------------+
| device  | count(device) |
+---------+---------------+
| Android |             1 |
| IOS     |             1 |
| Windows |             1 |
| Windows |             1 |
+---------+---------------+

将 queryset 的原始对象打印,发现该语句多了一个用于 group by 的字段,大概如下:

>>> print(queryset.query)
SELECT `table1`.`device`, COUNT(`table1`.`device`) FROM `table1` GROUP BY `table1`.`device`, `table1`.`create_time`

可以看到是 group by 之后多了 create_time 字段,这个字段是我在创建模型类的时候填写的默认排序,即 class meta 中的 ordering。在翻阅了不少东西过后,发现解决它就得从排序下手,要么删除默认排序,要么使用一个空的排序来重置它。于是上面的 django 代码可以改写成这样。

queryset = Table1.objects.values("device").annotate(Count("device")).order_by()

于是就这么正常了,至于空的 order_by,相当于 ORDER BY NULL。

上一篇:《Pytorch 模型推理及多任务通用范式》第三节作业


下一篇:mxgate是gpcopy同步速度的2倍