嵌套对象的查询集排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了嵌套对象的查询集排序相关的知识,希望对你有一定的参考价值。

我需要在我的项目中用REST API建立一个简单的嵌套评论系统。

有一些要求。

这个页面应该包含所有评论的分页,而不仅仅是上级评论。所以,如果有1条评论和20条来自其他用户的嵌套评论,那么在第一页应该显示,就像这样。

-评论1

-- 分评论1

-- ...

-- -- 分评论9

在第二页。

-- 副评论10

-- ...

-- -- 分评论19

在第三页。

-- 分评论20

而且从最少的数据库访问量来看,这应该是一个最优的解决方案。

我想知道自定义Queryset的排序,当每条评论后面都有嵌套的评论,像这样。

// Note, that ids follow in chaotic order

    id: 1,
    text: "Comment 1",
    parent: null
, 

    id: 5,
    text: "Sub comment 1 for Comment 1",
    parent: 1
, 

    id: 6,
    text: "Sub comment 2 for Comment 1",
    parent: 1
, 

    id: 2,
    text: "Comment 2",
    parent: null
, 

    id: 3,
    text: "Sub comment 1 for Comment 2",
    parent: 2
, 

    id: 4,
    text: "Sub comment 2 for Comment 2",
    parent: 2
, 

我也想过,也在google上搜索过Django -mptt,但不知道如何实现。你能不能给我一些建议,如何解决这个问题,并得到像我例子中的JSON?

答案

你也许可以用一个复合排序键来注释查询集。<parent>_<id> 孩童和刚 <id> 为根注释,并以此排序。在这个例子中,评论的排序键是 1, 1_5, 1_6, 2, 2_3, 2_4.

from django.db.models import CharField, Value as V
from django.db.models.functions import Concat

Comment.objects
    .annotate(sort_key=Case(
        When(parent__isnull=True, then=Concat('id', V('_0'), output_field=CharField())),
        When(parent__isnull=False, then=Concat('parent', V('_'), 'id', output_field=CharField())),
        output_field=CharField())
    .order_by('sort_key')

当然,这只是一个有效的解决方案,如果孩子们可以按照 id 而不需要按日期或类似的方式排序。如果你需要对子代有其他的排序顺序,你可能需要在聚合中对它们的顺序进行排序后,用一个索引来显式地注释它们。

请看

EDIT:将父母的排序键改为1_0。解决了int与char比较的问题。当然,转码也可以。

以上是关于嵌套对象的查询集排序的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch 7.x Nested 嵌套类型查询 ES 干货

使用 Django 的 ORM 和 Django Rest Framework 序列化嵌套关系的查询集的正确方法?

Mybatis结果集映射(resultMap)

sql语句 嵌套查询 排序

Elasticsearch聚合的嵌套桶如何排序

Mybatis学习第20节 -- 嵌套结果