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

时间:2011-07-26 19:22:06

标签: python mysql django orm django-orm

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

以下是数据的样子:

|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 Query看起来像这样:

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属性。

我也是根据annotate()调用之前和之后记录的.values()行为的逻辑方式尝试过的,但它没有按预期工作。当我尝试这个时:

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中可用的结果?

2 个答案:

答案 0 :(得分: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实际上不应该让我生成这样的查询,我基本上是在尝试不正确地解决我的问题。

答案 1 :(得分:0)

这在文档的注释部分中相当简单和详细,并且没有以前的版本可以手动设置组。

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