Wagtail:如何查询 child 页面的相关名称(内联模型)?

Wagtail : How do I query related names (inline models) of a child page?

我有两个页面:

文章页面和时间线页面。

TimelinePage 有一个与模型 TimelinePageEntry 相关的内联面板。

TimelinePage 显示所有 child TimelinePageEntry(s) 就好了。但是,当我尝试从 ArticlePage 获取所有 TimelinePageEntry(s) 时,它失败并出现异常。

当我尝试执行以下操作时,ArticlePage 失败并出现异常:

context['timeline_entries'] = timeline_page.timeline_entries.all()

这是models.py中三个类的源代码:

import datetime

from django.db import models
from modelcluster.fields import ParentalKey
from wagtail.admin.edit_handlers import FieldPanel, InlinePanel
from wagtail.core.fields import RichTextField
from wagtail.core.models import Orderable
from wagtail.core.models import Page


class ArticlePage(Page):
    date = models.DateField("Creation date", default=datetime.date.today)
    hero_biography = RichTextField(blank=True)

    content_panels = Page.content_panels + [
        FieldPanel('date'),
        FieldPanel('hero_biography'),
    ]

    subpage_types = [
        'articles.TimelinePage'
    ]

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request)
        timeline_pages = self.get_children().type(TimelinePage)
        timeline_page = timeline_pages[0]

        # prints "Page"
        print(type(timeline_page).__name__)
        
        # prints the title of the timeline page, so I know I'm getting a query result
        print(timeline_page.title)

        context['timeline_page'] = timeline_page

        # Throws an exception
        context['timeline_entries'] = timeline_page.timeline_entries.all()

        return context


class TimelinePage(Page):
    max_count_per_parent = 1
    subpage_types = []

    content_panels = Page.content_panels + [
        InlinePanel('timeline_entries', label="Timeline Entries")
    ]

    parent_page_type = [
        'articles.ArticlePage'
    ]

    def get_context(self, request, *args, **kwargs):
        # Prints "TimelinePage"
        print(type(self).__name__)

        # Prints a list of timeline entries
        print(repr(self.timeline_entries.all()))

        return super().get_context(request)


class TimelinePageEntry(Orderable):
    page = ParentalKey(TimelinePage, on_delete=models.CASCADE, related_name='timeline_entries')

    start_date = models.DateField()
    end_date = models.DateField(null=True, blank=True)

    line = RichTextField(max_length=90)

    panels = [
        FieldPanel('start_date'),
        FieldPanel('end_date'),
        FieldPanel('line'),
    ]

    class Meta(Orderable.Meta):
        ordering = ['-start_date']

看来我要做的事情应该很简单。 TimelinePage 是 child 的 文章页面。我可以从 ArticlePage 访问 TimelinePage(标题)的其他属性,但我对如何获取 TimelinePageEntries 感到困惑。

我得到的异常是:

    context['timeline_entries'] = timeline_page.timeline_entries.all()
AttributeError: 'Page' object has no attribute 'timeline_entries'

这是由于 Page 实例(仅包含所有页面类型共有的数据,例如标题)和您的特定 TimelinePage 子实例class 之间的区别(它提供对在 class 上定义的所有方法、字段和关系的访问)。

self.get_children() returns Page 类型的查询集;这是必要的,因为查询事先不知道结果中将包含哪些页面类型。 .type(TimelinePage) 将此过滤为仅给定类型的页面,但这仅作为现有查询集的过滤器 - 结果仍将保持为 Page objects,缺少 timeline_entries关系。

如果重写该行

timeline_pages = self.get_children().type(TimelinePage)

进入

timeline_pages = TimelinePage.objects.child_of(self)

然后这将确保结果作为 TimelinePage 实例返回,然后 timeline_entries 关系将按预期工作。