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
相关产品推荐
相关产品推荐

