Я думаю, это лучше всего объяснить на примере.
Вот как будут выглядеть данные:
|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 orm в django 1.3, я просто не могу найти подходящий способ сделать это. Если я сделаю что-то вроде этого:
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"
Это не вернет мне правильные результаты, так как группа неверна для того, что я хочу. Я полагаю, что в предыдущих версиях 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"
Может ли кто-нибудь указать мне правильный способ делать то, что я делаю, без какого-либо из следующих действий:
- Использование raw sql - какой смысл использовать orm, когда мне постоянно приходится генерировать свои собственные запросы?
- Использование .extra (select = {'latest': 'somequery'}) - почему я должен использовать подзапросы, когда совершенно правильный запрос без подзапросов может дать мне то, что я хочу.
- Использование нескольких запросов для получения одних и тех же данных - опять же, зачем мне делать несколько запросов, чтобы получить результаты, доступные в 1?