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