Ваш вопрос не совсем понятен: поскольку вы не сказали иначе, я собираюсь предположить, что вам все равно , какой элемент выбран для каждой категории, только то, что вам нужно один. Если это не так, обновите вопрос, чтобы уточнить.
tl; dr версия: нет документированного
способ явно использовать GROUP BY
заявления в Django, кроме как с помощью
сырой запрос. См. Внизу код для этого.
Проблема в том, что для выполнения того, что вы ищете в самом SQL, требуется небольшой взлом. Вы можете легко попробовать этот пример с помощью ввода sqlite3 :memory:
в командной строке:
CREATE TABLE category
(
id INT
);
CREATE TABLE item
(
id INT,
category_id INT
);
INSERT INTO category VALUES (1);
INSERT INTO category VALUES (2);
INSERT INTO category VALUES (3);
INSERT INTO item VALUES (1,1);
INSERT INTO item VALUES (2,2);
INSERT INTO item VALUES (3,3);
INSERT INTO item VALUES (4,1);
INSERT INTO item VALUES (5,2);
SELECT id, category_id, COUNT(category_id) FROM item GROUP BY category_id;
возвращает
4|1|2
5|2|2
3|3|1
Что именно вы ищете (один идентификатор элемента для каждого идентификатора категории), хотя и с посторонним счетом. Счетчик (или другая агрегатная функция) необходим для применения GROUP BY.
Примечание: при этом будут игнорироваться категории, в которых нет элементов, что выглядит как разумное поведение.
Теперь возникает вопрос, как это сделать в Django?
Очевидный ответ - использовать Поддержка агрегирования / аннотации Django , в частности, объединение annotete с значениями , как и , рекомендациями в других местах на запросы GROUP в Django.
Читая эти посты, может показаться, что мы могли бы достичь того, что искали, с помощью
Item.objects.values ( 'ID'). Аннотацию (unneeded_count = Count ( 'category_id'))
Однако это не работает. Здесь Django делает не просто GROUP BY "category_id"
, а группирует по все выбранные поля (т. Е. GROUP BY "id", "category_id"
) 1 . Я не верю, что есть способ (по крайней мере, в публичном API) изменить это поведение.
Решение состоит в том, чтобы вернуться к сырому SQL:
qs = Item.objects.raw('SELECT *, COUNT(category_id) FROM myapp_item GROUP BY category_id')
1 : обратите внимание, что вы можете проверить, с какими запросами работает Django:
from django.db import connection
print connection.queries[-1]
Edit:
Существует ряд других возможных подходов, но у большинства есть (возможно, серьезные) проблемы с производительностью. Вот пара:
1. Выберите предмет из каждой категории.
items = []
for c in Category.objects.all():
items.append(c.item_set[0])
Это более понятный и гибкий подход, но он имеет очевидный недостаток: он требует гораздо больше обращений к базе данных.
2. Используйте select_related
items = Item.objects.select_related()
, а затем выполните группировку / фильтрацию самостоятельно (в Python).
Опять же, это, возможно, более понятно, чем использование необработанного SQL и требует только одного запроса, но этот один запрос может быть очень большим (он будет возвращать все элементы и их категории), и выполнение группирования / фильтрации самостоятельно, вероятно, менее эффективно, чем позволить базе данных сделать это за вас.