嵌套对象的查询集排序
Queryset ordering for nested objects
我需要在我的项目中使用 REST 构建一个简单的嵌套评论系统 API。
有一些要求:
该页面应包含所有评论的分页,而不仅仅是父评论。所以,如果有 1 条评论和 20 条来自其他用户的嵌套评论,那么在第一页应该显示,如下所示:
-Comment 1
-- Sub comment 1
-- ...
-- Sub comment 9
On the second page:
-- Sub comment 10
-- ...
-- Sub comment 19
On the third page:
-- Sub comment 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>
的复合排序键对 children 和 <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')
如果 children 可以按 id
排序并且不需要按日期或类似排序,这当然只是一个有效的解决方案。如果您需要 children 的另一个排序顺序,您可能需要在聚合中对它们的顺序进行排序后用索引显式注释它们。
参见:
- https://docs.djangoproject.com/en/3.0/topics/db/aggregation/
- https://docs.djangoproject.com/en/3.0/ref/models/conditional-expressions/#case
- https://docs.djangoproject.com/en/3.0/ref/models/database-functions/#concat
编辑:
将 parents 的排序键更改为 1_0。解决了 int 与 char 比较的问题。当然,演员表也可以。
我需要在我的项目中使用 REST 构建一个简单的嵌套评论系统 API。
有一些要求:
该页面应包含所有评论的分页,而不仅仅是父评论。所以,如果有 1 条评论和 20 条来自其他用户的嵌套评论,那么在第一页应该显示,如下所示:
-Comment 1
-- Sub comment 1
-- ...
-- Sub comment 9
On the second page:
-- Sub comment 10
-- ...
-- Sub comment 19
On the third page:
-- Sub comment 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>
的复合排序键对 children 和 <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')
如果 children 可以按 id
排序并且不需要按日期或类似排序,这当然只是一个有效的解决方案。如果您需要 children 的另一个排序顺序,您可能需要在聚合中对它们的顺序进行排序后用索引显式注释它们。
参见:
- https://docs.djangoproject.com/en/3.0/topics/db/aggregation/
- https://docs.djangoproject.com/en/3.0/ref/models/conditional-expressions/#case
- https://docs.djangoproject.com/en/3.0/ref/models/database-functions/#concat
编辑: 将 parents 的排序键更改为 1_0。解决了 int 与 char 比较的问题。当然,演员表也可以。