Query.group_by в Django 1.9

Я перемещаю код с Django 1.6 до 1.9. В 1.6 у меня был этот код

models.py

class MyReport(models.Model):
    group_id    =   models.PositiveIntegerField(blank=False, null=False)

views.py

query = MyReport.objects.filter(owner=request.user).query
query.group_by = ['group_id']
entries = QuerySet(query=query, model=MyReport)

Запрос будет возвращать один объект для каждого 'group_id'; из-за того, как я его использую, любая строка таблицы с group_id будет выполнять роль представителя.

С 1.9 этот код нарушен. Запрос после второй строки выше:

SELECT "reports_myreport"."group_id", ... etc FROM "reports_myreport" WHERE "reports_myreport"."owner_id" = 1 GROUP BY "reports_myreport"."group_id", "reports_report"."otherfield", ...

В основном он перечисляет all поля таблицы в предложении group by, заставляя запрос возвращать всю таблицу.

Если в отладчике я вижу

query.group_by = ['group_by'] 

Не похоже, что query.group_by - это метод в 1.9, и в журналах изменений 1.7-1.9 не указано, что что-то изменилось.

Есть ли лучший способ - не в зависимости от внутренних вещей Django - я могу использовать для моего запроса?

Любой способ исправить мой текущий запрос?

Ответ 1

Вы можете использовать order_by(), чтобы получить упорядоченные результаты, в том же запросе, который вы можете заказать по второму критерию.

Если вы хотите получить группы, вам нужно будет перебирать коллекцию, чтобы получить эти значения.

Если вы используете все результаты, возвращаемые запросом, вы можете рассмотреть:

a) itertools.groupby, который вместо этого создает группу в памяти, но вы не должны использовать ее для больших наборов данных.

b) Другой вариант - использовать Manager.raw(), но вам нужно будет написать SQL внутри Django, например:

for report in MyReport.objects.raw('SELECT * FROM reporting_report GROUP by group_id'):
     print(report)

Это будет работать для больших наборов данных, но вы можете потерять совместимость с некоторыми механизмами баз данных.

Бонус:. Я рекомендую вам понять, что именно сделал старый код, прежде чем переписывать.