使用额外字段扩展 Wagtail 抽象模型的正确方法是什么?

What is the correct way to extend Wagtail abstract models with extra fields?

我有一个带有几个 StreamField 的抽象 Wagtail 模型。其中两个 StreamField 位于管理视图的单独选项卡中,它们已添加到 edit_handler.

class AbstractHomePage(Page):
    body = StreamField(
        HomePageStreamBlock(),
        default=''
    )
    headingpanel = StreamField(
        HeadingPanelStreamBlock(),
        default=''
    )
    sidepanel = StreamField(
        SidePanelStreamBlock(),
        default=''
    )

    class Meta:
        abstract = True

    search_fields = Page.search_fields + [index.SearchField('body')]

    content_panels = Page.content_panels + [
        StreamFieldPanel('body'),
    ]

    pagesection_panels = [
        StreamFieldPanel('headingpanel'),
        StreamFieldPanel('sidepanel'),
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels),
        ObjectList(pagesection_panels, heading='Page sections'),
        ObjectList(Page.promote_panels),
        ObjectList(Page.settings_panels, classname='settings'),
    ])

我想扩展这个模型并添加一个字段:

class Foo(AbstractHomePage):
    extra = models.TextField()

    Meta:
        verbose_name='Foo'

    content_panels = [
        AbstractHomePage.content_panels[0],     # title
        FieldPanel('extra'),
        AbstractHomePage.content_panels[-1]     # streamfield
    ]

添加新的 Foo 页面时,管理面板中唯一可用的字段是 AbstractHomePage 中的字段。在更新 Fooedit_handler:

之前,新添加的字段不可用
class Foo(AbstractHomePage):
    extra = models.TextField()

    Meta:
        verbose_name='Foo'

    content_panels = [
        AbstractHomePage.content_panels[0],     # title
        FieldPanel('extra'),
        AbstractHomePage.content_panels[-1]     # streamfield
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels),
        ObjectList(AbstractHomePage.pagesection_panels, heading='Page sections'),
        ObjectList(Page.promote_panels),
        ObjectList(Page.settings_panels, classname='settings'),
    ])

现在回答我的问题:我是不是做错了什么或没有遵循良好的编码习惯?

如果我必须为每个扩展模型更新 edit_handler,是否有更好的方法来做到这一点?每次都必须确保扩展 AbstractHomePage 的模型的新添加字段获得显式 "boilerplate" edit_handler 块感觉真的很难看。我认为这是对 DRY 原则的严重违反。

您必须在 Foo 中重新定义 edit_handler 的原因是 Python 从上到下评估 AbstractHomePage class 定义 - 在这一点上它遇到了这条线:

ObjectList(content_panels),

content_panels 被视为变量,而不是 class 属性,因此编辑处理程序是基于当时存在的 content_panels 列表构建的观点。在 subclass 中重新定义 content_panels 不能覆盖这个。

本质上,您正在寻找一种方法来推迟构造 edit_handler 直到定义了 subclass。我看不出直接这样做的好方法,但我认为你可以通过重写 the Page.get_edit_handler method:

来深入研究 Wagtail 的内部结构来实现它
from wagtail.utils.decorators import cached_classmethod

class AbstractHomePage(Page):
    ...
    @cached_classmethod
    def get_edit_handler(cls):
        edit_handler = TabbedInterface([
            ObjectList(cls.content_panels),
            ObjectList(cls.pagesection_panels, heading='Page sections'),
            ObjectList(cls.promote_panels),
            ObjectList(cls.settings_panels, classname='settings'),
        ])
        return edit_handler.bind_to_model(cls)