问题描述
我有一个抽象的Wagtail模型,有几个 StreamField
s。其中两个 StreamField
在管理视图中的另一个选项卡中,添加到 edit_handler
。pre $
class AbstractHomePage(页):
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_panel
ObjectList(pagesection_panels,heading ='Page sections'),
ObjectList(Page.promote_panels),
ObjectList(Page.settings_panels,classname ='settings'),
])
我想扩展此模型并添加一个字段:
class Foo(AbstractHomePage):
extra = models.TextField()
元:
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()
元:
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
,每次都感觉到明确的样板 edit_handler
块丑陋。
你必须重新定义 edit_handler的原因
在 Foo
中,Python从顶部到底部评估 AbstractHomePage
类定义 - 指出它遇到的行:
ObjectList(content_panels),
content_panels
被视为变量,而不是类属性,因此编辑处理程序是基于 content_panels
列表,因为它现在存在。在子类中重新定义 content_panels
不能覆盖此。
本质上,您正在寻找一种推迟方式构造edit_handler直到子类被定义。我看不到一个很好的方式直接进行,但是我想你可以通过一些挖掘Wagtail内部实现它,通过覆盖:
从$ w $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ b @cached_classmethod
def get_edit_handler(cls):
edit_handler = TabbedInterface([
ObjectList(cls.content_panels))
ObjectList(cls.pagesection_panels,heading ='页面部分) ,
ObjectList(cls.promote_panels),
ObjectList(cls.settings_panels,classname ='settings'),
])
返回edit_handler.bind_to_model(cls)
I have an abstract Wagtail model with a few StreamField
s. Two of these StreamField
s are in a separate tab in the admin view, which are added to the 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'),
])
I want to extend this model and add a field:
class Foo(AbstractHomePage):
extra = models.TextField()
Meta:
verbose_name='Foo'
content_panels = [
AbstractHomePage.content_panels[0], # title
FieldPanel('extra'),
AbstractHomePage.content_panels[-1] # streamfield
]
When adding a new Foo page, the only fields available in the admin panel are the fields from the AbstractHomePage
. The newly added field isn't available until I update Foo
's 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'),
])
And now to my question: Have I done something wrong or not followed good coding practices?
If I do have to update the edit_handler
for each extending model, is there a better way to do this? Having to ensure that newly added fields for models extending the AbstractHomePage
gets the explicit "boilerplate" edit_handler
block each time feels really ugly. I see it as a massive violation of the DRY principle.
The reason you have to redefine edit_handler
in Foo
is that Python evaluates the AbstractHomePage
class definition from top to bottom - at the point that it encounters the line:
ObjectList(content_panels),
content_panels
is treated as a variable, not a class property, and so the edit handler is built based on the content_panels
list as it existed at that point. Redefining content_panels
in the subclass can't override this.
Essentially, you're looking for a way to defer constructing the edit_handler until the subclass has been defined. I can't see a good way of doing that directly, but I think you could achieve it with a bit of digging into Wagtail internals, by overriding 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)
这篇关于使用额外字段扩展Wagtail抽象模型的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!