使用额外字段扩展 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
中的字段。在更新 Foo
的 edit_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)
我有一个带有几个 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
中的字段。在更新 Foo
的 edit_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:
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)