You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django/Wagtail按父节点返回单个最新RecordPage子页面的问题

解决Wagtail页面树形结构中按父节点获取最新子页面的问题

你遇到的核心问题是:Wagtail的RecordPage继承自Page模型,而Page并没有直接暴露名为parent的数据库字段(它的树形关系是通过path/depth以及parent_id外键实现的),所以直接用distinct("parent")会导致Django找不到对应字段的错误。下面给你两种可行的解决方案:

方案一:利用父页面ID分组去重(适用于PostgreSQL)

PostgreSQL支持按指定字段进行distinct操作,我们可以先通过annotate获取父页面的ID,再按父ID分组并取每个组内最新的页面:

from django.db.models import F

# 获取每个父节点下最新的RecordPage,再取前5条最新的
latest_record_pages = (
    RecordPage.objects.live()
    # 关联到Page模型的parent_id字段(因为RecordPage继承自Page)
    .annotate(parent_page_id=F('page_ptr__parent_id'))
    # 先按父页面ID分组,再按发布时间倒序,确保每个父节点下最新的页面排在前面
    .order_by('parent_page_id', '-first_published_at')
    # 按父页面ID去重,每个父节点只保留第一条(也就是最新的那个)
    .distinct('parent_page_id')
    # 最后再按发布时间倒序,取前5条展示在首页
    .order_by('-first_published_at')[:5]
)

方案二:使用窗口函数(通用数据库支持)

如果你的项目用的是MySQL等不支持字段级distinct的数据库,或者想更通用的实现,可以用Django的窗口函数来实现分组取最新:

from django.db.models import Window, F
from django.db.models.functions import RowNumber

latest_record_pages = (
    RecordPage.objects.live()
    # 按父页面ID分区,每个分区内按发布时间倒序编号
    .annotate(
        row_num=Window(
            partition_by=F('page_ptr__parent_id'),
            order_by=F('first_published_at').desc()
        )
    )
    # 只保留每个分区的第一条(也就是最新的那个页面)
    .filter(row_num=1)
    # 按发布时间倒序取前5条
    .order_by('-first_published_at')[:5]
)

额外提示:过滤特定父节点类型

因为你提到RecordPage仅能添加到特定节点,你可以在查询中加上父页面类型的过滤,确保只获取符合要求的页面:

# 假设你的特定父页面模型是ParentPage
latest_record_pages = (
    RecordPage.objects.live()
    .filter(page_ptr__parent__specific_type='your_app.ParentPage')
    # 后续的annotate/order_by逻辑同上
)

内容的提问来源于stack exchange,提问作者Diogo Freire

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:50:04