Django - 对线程评论的查询集进行排序

发布于 2024-12-01 12:52:28 字数 1040 浏览 0 评论 0原文

我正在使用 django-threadedcomments,但是这个问题通常也适用于对 QuerySet 进行排序。

QuerySet中的评论对象有两个重要的字段,tree_path和submit_date。 tree_path 的形式为“a/b/.../z”,其中“a”是树中的最高阶索引,“b”是树中的最低阶索引。因此第一个根注释的 tree_path 将为“1”。该注释的子级的 tree_path 为“1/1”。 “1”的另一个子级的 tree_path 将为“1/2”。第二个根注释的 root_path 为“2”,等等...

查询集“qs”按上面的方式排序,注释按线程顺序排列,最旧的注释位于顶部。上面示例的 tree_paths 看起来像 [1, 1/1, 1/2, 2]。我想先将每个级别的评论与最新的评论进行排序。因此 QuerySet 应该是 [2, 1, 1/2, 1/1]。

我该怎么做?

我可以使用以下方法仅对根级评论进行排序:

qs = qs.extra(select={ 'tree_path_root': 'SUBSTRING(tree_path, 1, 1)' })
       .order_by('%stree_path_root' % ('-'), 'tree_path')

但我无法弄清楚如何同时对非根级评论进行排序。我尝试过类似的方法:

qs = qs.extra(select={ 'tree_path_root': 'SUBSTRING(tree_path, 1, 1)' 
                       'tree_path_sec' : 'SUBSTRING(tree_path, 3, 1)'})
       .order_by('%stree_path_root' % ('-'), '%stree_path_sec' % ('-'), 'tree_path')

但这会破坏评论的线索。

有什么建议吗?谢谢!

I am using django-threadedcomments, however the question also applies generally to sorting a QuerySet.

The comment objects in the QuerySet have two important fields, tree_path and submit_date. tree_path is of the form "a/b/.../z" where 'a' is the highest-order index in the tree, and 'b' is the lowest order index in the tree. So the first root comment will have a tree_path of '1'. A child of that comment will have a tree_path of '1/1'. Another child of '1' will have a tree_path of '1/2'. The second root comment will have a root_path of '2', etc...

The QuerySet "qs" is sorted like above, with comments in threaded order with the oldest comments on top. Just the tree_paths of the above example would look like [1, 1/1, 1/2, 2]. I would like to sort each level of comments with the newest comments first. So the QuerySet instead should be [2, 1, 1/2, 1/1].

How can I do this?

I can sort just the root level comments by using:

qs = qs.extra(select={ 'tree_path_root': 'SUBSTRING(tree_path, 1, 1)' })
       .order_by('%stree_path_root' % ('-'), 'tree_path')

But I cannot figure out how to sort the non-root comments at the same time. I've tried something like:

qs = qs.extra(select={ 'tree_path_root': 'SUBSTRING(tree_path, 1, 1)' 
                       'tree_path_sec' : 'SUBSTRING(tree_path, 3, 1)'})
       .order_by('%stree_path_root' % ('-'), '%stree_path_sec' % ('-'), 'tree_path')

But that destroys the threading of the comments.

Any suggestions? Thanks!

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

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

发布评论

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

评论(2

独木成林 2024-12-08 12:52:28

我意识到自从您发布以来已经有一段时间了..所以您现在可能已经有了答案,或者也许您已经继续前进。无论如何,在这里...:)

您误解了 django-threadedcomments 应用程序中的 tree_path 结构。永远不会有 1/1 的 tree_path,因为每个路径段都是该 ThreadedComment 的唯一主键。

如果您从 ThreadedComment 1 开始,并添加回复,您将获得 1/2 路径。然后,如果您添加额外的顶级帖子,它将获得路径 3。这将为您提供:

1
1/2
3

如果您再次回复第一篇帖子,您将得到:

1
1/2
1/4
3

现在解决排序问题。我尝试过进行类似的排序(通过投票分数,类似于 reddit),但发现没有简单的方法来做到这一点。然而,这里有一个你可以使用的递归方法:(它很丑陋,而且很慢......但它是一个起点)

def sort_comments(tree):
    final_tree = []
    root_comments = [c for c in tree if c.tree_path.count('/') == 0]
    root_comments.sort(key=lambda comment: comment.submit_date, reverse=True)
    for comment in root_comments:
        final_tree.append(comment)
        append_and_sort_children(final_tree, tree, comment)
    return final_tree


def append_and_sort_children(final_tree, tree, parent):
    children = [c for c in tree if c.parent_id == parent.id]
    children.sort(key=lambda comment: comment.submit_date, reverse=True)
    for comment in children:
        final_tree.append(comment)
        append_and_sort_children(final_tree, tree, comment)

使用这个方法,只需传入该模型的整个查询注释集,Python 就会对它们进行排序你。 :)

这会给你最终的结果:

3
1
1/4
1/2

如果有人有办法缩短这个时间,请随意贡献。

I realize this has been a little while since you posted.. so you may have an answer by now, or maybe you have moved on. Regardless, here you go... :)

You are misunderstanding the tree_path structure in the django-threadedcomments application. There will never be a tree_path of 1/1, as each path segment is the unique primary key of that ThreadedComment.

If you start with ThreadedComment 1, and add a reply, you will get a path of 1/2. Then if you add an additional top-level post, it would get the path 3. This would give you:

1
1/2
3

And if you reply to the first post again, you would get:

1
1/2
1/4
3

Now to address the sorting issue. I have attempted to do a similar sorting (by a voting score, similar to reddit), and found no easy way to do it. However, here is a recursive method that you can use: (It is ugly, and slow... but its a starting point)

def sort_comments(tree):
    final_tree = []
    root_comments = [c for c in tree if c.tree_path.count('/') == 0]
    root_comments.sort(key=lambda comment: comment.submit_date, reverse=True)
    for comment in root_comments:
        final_tree.append(comment)
        append_and_sort_children(final_tree, tree, comment)
    return final_tree


def append_and_sort_children(final_tree, tree, parent):
    children = [c for c in tree if c.parent_id == parent.id]
    children.sort(key=lambda comment: comment.submit_date, reverse=True)
    for comment in children:
        final_tree.append(comment)
        append_and_sort_children(final_tree, tree, comment)

Using this, simply pass in your entire query set of comments for that model, and python will sort them for you. :)

This will give you the final result of:

3
1
1/4
1/2

If anyone has a way to shorten this, feel free to contribute.

爱殇璃 2024-12-08 12:52:28

首先只选择根评论,对它们进行排序,然后选择子评论并对它们进行排序,最后连接两组评论怎么样?那行得通吗?

How about selecting just the root comments first, ordering them and then selecting the child comments and ordering them and finally concatenating both sets? Will that work?

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