【问题标题】:Queryset ordering for nested objects嵌套对象的查询集排序
【发布时间】:2020-10-04 22:28:51
【问题描述】:

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

有一些要求:

该页面应包含所有 cmets 的分页,而不仅仅是父 cmets。因此,如果有 1 条评论和 20 条来自其他用户的嵌套 cmets,则应在第一页显示,如下所示:

-评论1

-- 子评论1

-- ...

-- 子评论9

在第二页:

-- 子评论10

-- ...

-- 子评论 19

在第三页:

-- 子评论 20

就最少的数据库访问而言,它应该是最佳解决方案。

我想知道自定义 Queryset 排序,当每个评论后跟嵌套的 cmets 之后,就像这样:

// 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
}, 

我也想过和谷歌有关 Django-mptt,但不知道如何实现它。您能建议我如何解决这个问题并像我的示例中那样获取 JSON 吗?

【问题讨论】:

    标签: python django django-rest-framework django-queryset django-mptt


    【解决方案1】:

    您也许可以使用来自<parent>_<id> 的复合排序键为子级注释查询集,而只需<id> 为根 cmets 并按此排序。在示例中,cmets 将具有排序键 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 排序并且不需要按日期或类似排序,这当然是一个有效的解决方案。如果您需要对子项进行其他排序顺序,您可能需要在对它们在聚合中的顺序进行排序后使用索引显式注释它们。

    见:

    编辑: 将父母的排序键更改为 1_0。解决了 int 与 char 比较的问题。当然,演员表也可以。

    【讨论】:

    • 谢谢!但我发现它没有以正确的方式工作,因为id 像 int 一样序列化。因此,我们对 int 和 str 类型进行了比较。例如,1 和 '1_1'
    • 我为父母修改了排序键以避免这个问题。您还可以使用强制转换来转换 ID:docs.djangoproject.com/en/3.0/ref/models/database-functions/…
    猜你喜欢
    • 2017-01-15
    • 1970-01-01
    • 2021-10-02
    • 2013-06-03
    • 2021-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多