我可以在 django 1.3 的 orm 中控制 GROUP BY 吗?

Posted

技术标签:

【中文标题】我可以在 django 1.3 的 orm 中控制 GROUP BY 吗?【英文标题】:Can I control the GROUP BY in django 1.3's orm? 【发布时间】:2011-10-13 16:51:58 【问题描述】:

我认为这最好用一个例子来解释。

数据如下所示:

|project            |
|id|name            |
|1 |some project    |
|2 |my other project|

|run                                  |
|id|project_id|start_time   |result   |
|1 |1         |1305732581845|something|
|2 |1         |1305732593721|nothing  |
|3 |2         |1305732343721|nothing  |
|4 |2         |1305732556821|something|

我希望能够从每个项目的最新运行中获取整个记录集。 SQL 查询看起来像这样:

SELECT *, MAX("run"."start_time")
FROM "run"    
LEFT OUTER JOIN "project" ON ("run"."project_id" = "project"."id") 
GROUP BY "project"."id"

这将为我返回项目最新运行的两个表中的所有列,这很棒,这正是我所需要的。

因此,在尝试在 django 1.3 中找到等效的 django orm 时,我根本找不到合适的方法。如果我这样做:

Run.objects.annotate(Max('start_time'))

生成的 SQL 查询将如下所示:

SELECT 
"run"."id", "run"."result", "run"."project_id", "project"."id", "project"."name", 
MAX("run"."start_time")
FROM "run"
LEFT OUTER JOIN "project" ON ("run"."project_id" = "project"."id")
GROUP BY "run"."id", "run"."result", "run"."project_id", "project"."id", "project"."name"

这不会返回正确的结果,因为 group by 不符合我的要求。我相信在以前版本的 django 中,以下内容会在查询中正确明确地设置 group by 子句,但在 1.3 中似乎不起作用:

q = Run.objects.annotate(Max('start_time'))
q.query.group_by = [("project", "id")]

在 1.3 中,这会生成与不手动修改查询中的 group_by 属性完全相同的查询。

我还尝试了这种基于 .values() 在 annotate() 调用前后的记录行为的合乎逻辑的方法,但它没有按预期工作。当我尝试这个时:

q = Run.objects.values('project__id').annotate(Max('start_time')).values('id')

我最终得到了这样的查询:

SELECT 
"run"."id", "run"."project_id"
MAX("run"."start_time")
FROM "run"
LEFT OUTER JOIN "project" ON ("run"."project_id" = "project"."id")
GROUP BY "run"."id", "run"."project_id"

如果没有以下任何一项,谁能指出我正在做的事情的正确方法:

使用原始 sql - 当我必须经常生成自己的查询时,使用 orm 有什么意义? 使用 .extra(select = 'latest': 'somequery') - 当没有子查询的完全有效的查询可以给我想要的东西时,为什么我必须使用子查询。 使用多个查询来获取相同的数据 - 同样,为什么我必须进行多个查询才能获得 1 中可用的结果?

【问题讨论】:

【参考方案1】:

tl;dr:Django 确实允许您控制 group by 子句,但它限制它在所有 SQL 风格中工作,所以我不能做我想做的事。

有人向我指出,我尝试使用 django ORM 生成的原始查询实际上并不适用于所有类型的 SQL。这是我正在寻找的查询的复习:

SELECT *, MAX("run"."start_time")
FROM "run"    
LEFT OUTER JOIN "project" ON ("run"."project_id" = "project"."id") 
GROUP BY "project"."id"

如果一个人试图选择 MSSQL 中 GROUP BY 中没有的东西,他们实际上会得到一个错误。所以在我看来,django 实际上不应该让我生成这样的查询,而我实际上是在试图错误地解决我的问题。

【讨论】:

【参考方案2】:

这在文档的注释部分相当简单和详细,在以前的任何版本中都不能手动设置分组依据。

YourModel.objects.values('this_is_your_group_by', 'even_a_second_field').annotate(sum=Sum('your_field'))

【讨论】:

这不会返回每一行的整个记录​​集。它只会给我值列表中列的值。这意味着我无法在不按列分组的情况下从列中获取数据,不幸的是,我需要运行 ID。 `values('groupings,...).annotate().values('more_fields_to_show_here') 确保将注释添加的字段名称添加到注释后的值术语中 你应该真的读完了docs.djangoproject.com/en/1.3/topics/db/aggregation/… 我忘了提到这是我尝试的第一种方法,因为根据文档,这似乎是合乎逻辑的方法。它并没有按预期工作。后面的值调用中的所有值最终都在 group_by 子句中。我已经阅读了文档,除非我做错了什么,否则它似乎没有按预期工作。我将更新原始问题以说明我已经尝试过这个以及结果是什么,这只是我写问题时的疏忽。

以上是关于我可以在 django 1.3 的 orm 中控制 GROUP BY 吗?的主要内容,如果未能解决你的问题,请参考以下文章

Django ORM查询无法选择新对象

Django orm

在 Celery 任务中使用 Django 的 ORM

Django ORM - 检索数据时出错 -

使用php写入django ORM

在 Django ORM 中,一个“学生-课程”模型设计