Django:每个外键返回一个过滤对象

发布于 2024-09-07 00:12:23 字数 1127 浏览 9 评论 0原文

是否可以返回每个外键仅返回一个对象的查询集?

例如,我希望从 django_comments 获取最新评论,但我只想每个对象有一条评论(最新评论),即仅返回某个对象的最新评论并排除该对象的所有过去评论。我想这类似于 django_comments.content_type 和 django_comments.object_pk 上的 sql group_by 。

++添加信息++

最终目标是创建一个活动评论“线程”列表,按具有最新评论的线程显示/排序,就像您的标准讨论板,其主题按最近的活动列出。

我认为执行此操作的最佳方法是获取最新评论,然后按内容类型和 object_pk 对它们进行排序或分组,以便每个相关内容对象仅返回一条评论(最新)。然后我可以使用该评论来获取我需要的所有信息,因此“线程”一词的使用很宽松,因为我实际上只是抓住一条评论并关注它的 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 %}

再次感谢!

Is it possible to return querysets that return only one object per foreign key?

For instance, I want the to get the latest comments from django_comments, but I only want one comment (the latest comment) per object, i.e., only return the latest comment on an object and exclude all the past comments on that object. I guess this would be similar to a sql group_by on django_comments.content_type and django_comments.object_pk.

++ADDED INFO++

The end goal is to create a list of active comment "threads" displayed/ordered by which thread has the most recent comment, just like your standard discussion board whose topics are listed by recent activity.

I figure the best way to do this would be grabbing the latest comments, and then sorting or grouping them by content type and object_pk so that only one comment (the latest) is returned per related content object. I can then use that comment to get all the info I need, so the word thread is used loosely since I'm really just grabbing a comment and following it's pk's.

The MODEL is django_threadedcomments which extends django_comments with some added fields for trees, children, and parents.

VIEW:

...this returns all comments including all instances of parent

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

...and this is ideal

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]

TEMPLATE:

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

Thanks again!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

ま昔日黯然 2024-09-14 00:12:23

这在 SQL 中是一件相当困难的事情;你可能无法通过 ORM 来完成它。

您不能为此使用 GROUP BY。它用于告诉 SQL 如何对项目进行分组以进行聚合,但这不是您在这里所做的。 “SELECT x, y FROM table 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 触发器来自动处理此更新。

This is a fairly difficult thing to do in SQL at all; you probably won't be able to do it through the ORM.

You can't use GROUP BY for this. That's used for telling SQL how to group items for aggregation, which isn't what you're doing here. "SELECT x, y FROM table GROUP BY x" is illegal SQL, because the value of y is meaningless.

Let's look at this with a clear schema in mind:

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);

The most elegant way I've seen for doing this is Postgresql 8.4's windowing functions.

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;

That'll select the first comment for each object by date, newest first. If you don't see what this is doing, execute the inner SELECT on its own and watch how it generates rank(), which makes it pretty straightforward.

I know other ways of doing this with Postgresql, but I don't know how to do this in other databases.

Trying to compute this dynamically is likely to give you serious headaches--and it takes more work to make these complex queries perform well, too. Chances are you're better off doing this the simple way: store a last_comment_id field for each object and update it when a comment is added or deleted, so you can just join and sort. You could probably use SQL triggers to handle this updating automatically.

沐歌 2024-09-14 00:12:23

谢谢格伦和 vdboor。同意,所提出的想法会增加 sql 的复杂性,并将严重影响性能。

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

干杯,

jnh

Thanks Glenn and vdboor. Agreed, the proposed idea creates way to much sql complexity and will seriously impact performance.

The last_comment_id suggestion is very good, but I believe that for my particular situation the best thing to do is create a separate "THREAD" model that stores the content_type and object_pk of the original object commented upon as well as the id and timestamp of the object's last comment, among a few other things. This will allow simple content object lookups and chronologically filtered querysets, and will make what's happening under the hood more closely mirror the front-end presentation, which is probably a good idea for posterity. :)

Cheers,

jnh

一笑百媚生 2024-09-14 00:12:23

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

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

Consider storing the last post as a foreign key somewhere (e.g. in the parent object table). Each time a message is posted or deleted, update this key.

Yes, it's duplication, but worth considering. Having to run complex queries for each request (especially the index page) could take your application performance down. This is the pragmatic way to get the desired effect without losing performance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文