使用额外字段扩展Wagtail抽象模型的正确方法是什么? [英] What is the correct way to extend Wagtail abstract models with extra fields?

查看:157
本文介绍了使用额外字段扩展Wagtail抽象模型的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个抽象的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内部实现它,通过覆盖 Page.get_edit_handler 方法

从$ 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 StreamFields. Two of these StreamFields 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抽象模型的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆