Wagtail CMS自定义管理Panel如何传入当前页面实例或Page.id
问题描述
通用Wagtail开发场景下,需要新增自定义管理Panel用于罗列关联内容,查询关联内容时需要拿到当前模型实例(至少是实例ID)传入面板,在模型的管理面板列表属性中配置时,该如何实现这个需求?
以ArtistPage开发场景为例:需要在页面编辑器中新增一个面板,罗列与当前ArtistPage关联的WorkPages,最初尝试的写法无法正常运行:
from wagtail.models import Page class ArtistPage(Page): # 其他字段定义省略 content_panels = [ # 其他面板省略 ListWorksPanel(artist=self), # 该写法无法生效 ]
最开始参考官方HelpPanel的实现编写自定义面板,初始代码如下:
from wagtail.admin.panels import Panel class ListWorksPanel(Panel): def __init__(self, artist="", template="admin/list_works_panel.html", **kwargs): super().__init__(**kwargs) self.artist = artist self.template = template def clone_kwargs(self): kwargs = super().clone_kwargs() del kwargs["help_text"] kwargs.update( artist=self.artist, template=self.template, ) return kwargs class BoundPanel(Panel.BoundPanel): def __init__(self, panel, instance, request, form): super().__init__(panel, instance, request, form) self.template_name = self.panel.template self.artist = self.panel.artist
这个问题本质属于Python语法范畴:普通函数内传递self的逻辑是明确的,但当面板类作为列表元素定义在模型类属性中时,该如何正确传递当前实例的self? 最初猜测需要重写ArtistPage的__init__()方法实现,但不确定具体写法,同时也想明确向其他类传递self的符合Python规范的实现方式。
解决方案
不需要重写模型的__init__方法,只需要在BoundPanel类中实现get_context_data方法即可满足需求,修改后模板中可以正常访问关联作品数据,最终可运行代码如下:
class ListWorksPanel(Panel): def __init__(self, artist="", template="admin/list_works_panel.html", **kwargs): super().__init__(**kwargs) self.artist = artist self.template = template def clone_kwargs(self): kwargs = super().clone_kwargs() del kwargs["help_text"] kwargs.update( artist=self.artist, template=self.template, ) return kwargs class BoundPanel(Panel.BoundPanel): def __init__(self, panel, instance, request, form): super().__init__(panel, instance, request, form) self.template_name = self.panel.template self.artist = self.panel.artist def get_context_data(self, parent_context): context = super().get_context_data(parent_context) # 直接通过self.instance获取当前绑定的页面实例,查询关联作品 context['works'] = self.instance.works.all() return context
Wagtail的面板机制会在编辑页面渲染时,自动将当前正在编辑的模型实例传入BoundPanel的instance参数,不需要在模型类定义阶段手动传递self,直接在BoundPanel的方法中访问self.instance即可拿到当前模型对象,是符合框架设计和Python规范的实现方式。
内容的提问来源于stack exchange,提问作者Fuchsi
相关产品推荐
相关产品推荐

