Django: вернуть один отфильтрованный объект на внешний ключ - PullRequest
2 голосов
/ 20 июня 2010

Можно ли вернуть наборы запросов, которые возвращают только один объект на внешний ключ?

Например, я хочу получить последние комментарии от django_comments, но я хочу, чтобы только один комментарий (последний комментарий) на объект, т. Е. Возвращал только последний комментарий на объект и исключал все прошлые комментарии на этот объект , Я думаю, это будет похоже на sql group_by на django_comments.content_type и django_comments.object_pk.

++ ДОБАВЛЕННАЯ ИНФОРМАЦИЯ ++

Конечная цель - создать список «обсуждений» активных комментариев, упорядоченных по темам, у которых есть последний комментарий, как на стандартной доске обсуждений, темы которой перечислены по последним действиям.

Я полагаю, что лучший способ сделать это - получить последние комментарии, а затем отсортировать или сгруппировать их по типу содержимого и object_pk, чтобы на один связанный объект содержимого возвращался только один комментарий (последний). Затем я могу использовать этот комментарий, чтобы получить всю необходимую мне информацию, поэтому слово поток используется свободно, так как я на самом деле просто беру комментарий и следую за его комментариями.

МОДЕЛЬ - это django_threadedcomments, которая расширяет django_comments некоторыми добавленными полями для деревьев, детей и родителей.

ВИД:

... это возвращает все комментарии, включая все экземпляры родителя

comments = ThreadedComment.objects.all().exclude(is_public='0').order_by("-submit_date")

... и это идеально

comments = ThreadedComment.objects.all().exclude(is_public='0').order_by("submit_date").[plus sorting logic to exclude multiple instances of the same object_pk and content_type]

ШАБЛОН:

{% for comment in comments %}

TITLE: {{comment.content_object.title}}

STARTED BY : {{comment.content_object.user}}

MOST RECENT REPLY : {{comment.user}} on {{comment.submit_date}}

{% endfor %}

Еще раз спасибо!

Ответы [ 3 ]

2 голосов
/ 21 июня 2010

Это довольно сложно сделать в SQL вообще;вы, вероятно, не сможете сделать это через ORM.

Вы не можете использовать GROUP BY для этого.Это используется для указания SQL, как группировать элементы для агрегации, а это не то, что вы здесь делаете.«SELECT x, y FROM таблицы GROUP BY x» является недопустимым SQL, поскольку значение y не имеет смысла.

Давайте рассмотрим это с ясной схемой:

CREATE TABLE objects ( id INTEGER PRIMARY KEY, name VARCHAR );
CREATE TABLE comments ( object_id INTEGER REFERENCES objects (id), text VARCHAR NOT NULL, date TIMESTAMP NOT NULL );

INSERT INTO objects (id, name) VALUES (1, 'object 1'), (2, 'object 2');
INSERT INTO comments (object_id, text, date) VALUES
   (1, 'object 1 comment 1', '2010-01-02'),
   (1, 'object 1 comment 2', '2010-01-05'),
   (2, 'object 2 comment 1', '2010-01-08'),
   (2, 'object 2 comment 2', '2010-01-09');

SELECT * FROM objects o JOIN comments c ON (o.id = c.object_id);

Самый элегантный способ, который я когда-либо видел, это оконные функции Postgresql 8.4.

SELECT * FROM (
    SELECT
        o.*, c.*,
        rank() OVER (PARTITION BY object_id ORDER BY date DESC) AS r
    FROM objects o JOIN comments c ON (o.id = c.object_id)
) AS s
WHERE r = 1;

, который выберет первый комментарий для каждого объекта по дате, самый новый сначала.Если вы не видите, что это делает, выполните внутренний SELECT самостоятельно и посмотрите, как он генерирует rank (), что делает его довольно простым.

Я знаю другие способы сделать это с Postgresql, ноЯ не знаю, как это сделать в других базах данных.

Попытка вычислить это динамически может привести к серьезным головным болям - и для того, чтобы эти сложные запросы работали хорошо, требуется больше работы.Скорее всего, вам лучше сделать это простым способом: сохраните поле last_comment_id для каждого объекта и обновите его, когда комментарий будет добавлен или удален, так что вы можете просто присоединиться и отсортировать.Возможно, вы могли бы использовать триггеры SQL для автоматической обработки этого обновления.

0 голосов
/ 21 июня 2010

Спасибо, Гленн и vdboor.Согласитесь, предложенная идея создает много проблем и серьезно повлияет на производительность.

Предложение last_comment_id очень хорошо, но я считаю, что для моей конкретной ситуации лучше всего создать отдельную модель "THREAD", которая хранит content_type и object_pk исходного объекта, прокомментированного, а такжеid и метка времени последнего комментария объекта, среди прочего.Это позволит осуществлять простой поиск объектов контента и хронологически отфильтрованные наборы запросов, а также сделает происходящее под капотом более близким отражением интерфейсной презентации, что, вероятно, является хорошей идеей для потомков.:)

Ура,

Джн

0 голосов
/ 21 июня 2010

Подумайте о сохранении последнего сообщения как внешнего ключа где-нибудь (например, в таблице родительских объектов) Каждый раз, когда сообщение публикуется или удаляется, обновляйте этот ключ.

Да, это дублирование, но стоит задуматься. Необходимость выполнять сложные запросы для каждого запроса (особенно страницы индекса) может снизить производительность вашего приложения. Это прагматичный способ получить желаемый эффект без потери производительности.

...