2010-06-20 59 views
2

是否可以返回仅为每个外键返回一个对象的查询集?例如,我想要从django_comments获取最新评论,但我只希望每个对象有一条评论(最新评论),即只返回对象的最新评论,并排除所有过去的评论。目的。我想这应该类似于django_comments.content_type和django_comments.object_pk上的sql group_by。Django:为每个外键返回一个过滤对象

++ ADDED INFO ++

的最终目标是创建显示活动评论“线程” /由线程最近的评论,就像你的标准的讨论板,其主题近期上市有序列表活动。

我想最好的办法是抓住最新的评论,然后按内容类型和object_pk对它们进行排序或分组,以便每个相关内容对象只返回一个评论(最新)。然后,我可以使用该评论来获取我需要的所有信息,因此单词线程的使用松散,因为我只是抓住评论并跟随它的PK。

MODEL是django_threadedcomments,它扩展了django_comments,为树,子和父母添加了一些字段。

VIEW:

...这将返回包括家长

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 %} 

再次感谢!

+1

基本上,你想要一个SQL'LIMIT 1'('[0]'一个Django的查询),但是你想要的每线程?你能告诉我们你的“得到所有评论”Django查询的样子,所以我们可以告诉你如何改变它? – 2010-06-20 18:08:53

+0

我已更新我的问题,谢谢! – jnh 2010-06-20 19:08:18

+0

使用不同。看看这个答案http://stackoverflow.com/a/14293530/632182 – Christoffer 2016-04-08 13:41:19

回答

2

这在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触发器自动处理此更新。

-1

考虑将最后一篇文章存储为某处的外键(例如,在父对象表中)。每次发布或删除消息时,都要更新此密钥。

是的,它是重复的,但值得考虑。不得不为每个请求运行复杂的查询(尤其是索引页)可能会降低应用程序的性能。这是在不失性能的情况下获得理想效果的实用方法。

0

谢谢格伦和vdboor。同意,所提出的想法创造了很多SQL复杂性的方式,并会严重影响性能。

last_comment_id建议非常好,但我相信对于我的特殊情况,最好的办法是创建一个单独的“THREAD”模型,存储原始对象的content_type和object_pk以及id和对象的最后评论的时间戳,以及其他一些事情。这将允许简单的内容对象查找和按时间顺序过滤的查询集,并且将使得引擎盖下发生的事情更贴近前端展示,这对于后代来说可能是一个好主意。 :)

干杯,

JNH