Wagtail:如何将按钮 "add subpage" 添加到自定义列表视图(IndexView)的操作列表中?
Wagtail: How to add button "add subpage" to the action list of a custom listing view (IndexView)?
我正在为每个用户构建管理菜单 w/o 资源管理器视图和自定义 ModelAdmin
个实例。
@hooks.register('construct_main_menu')
def hide_page_explorer_menu_item(request, menu_items):
if request.user.username == 'user1':
menu_items[:] = [item for item in menu_items if item.name not in [
'explorer',
]
]
class CustomAdmin(ModelAdmin):
model = MyPage
menu_label = 'custom ModelAdmin'
list_display = ('title', "live")
list_filter = ("date")
search_fields = ("title")
modeladmin_register(CustomAdmin)
但是生成的列表视图的操作列表(即上下文菜单)缺少资源管理器视图提供的一些功能。
我特别需要"ADD CHILDPAGE"。我知道钩子 register_page_listing_buttons
。但是您只能为资源管理器视图操作列表注册按钮。
是否可以将按钮 "add subpage" 添加到自定义列表视图的操作列表中?
Explorer 列表视图:
自定义 ModelAdmin 列表视图:
回答
ModelAdmin
不使用相同的系统来构建视图中列出的按钮。
相反,它有一个 'helper classes' 的概念,这些用于生成 URLs 和权限检查,这反过来又用于生成出现在各种视图中的按钮。
https://docs.wagtail.io/en/stable/reference/contrib/modeladmin/primer.html?highlight=primer
您将需要在 ModelAdmin
实例上设置一个自定义 button_helper_class,它将在您的 IndexView
中生成您想要的自定义按钮。为此,您需要使用自定义 get_buttons_for_obj
方法导入和扩展 PageButtonHelper
class,该方法将 return 按钮列表。
代码示例
# wagtail_hooks.py
from django.urls import reverse
from wagtail.contrib.modeladmin.options import (ModelAdmin, modeladmin_register)
from wagtail.contrib.modeladmin.helpers import (PageAdminURLHelper, PageButtonHelper)
# MyPage model import not included but will be needed
class CustomPageAdminURLHelper(PageAdminURLHelper):
def get_action_url(self, action, *args, **kwargs):
if action == 'add-child':
# note: add_subpage is used as the internal name for adding child pages
url_name = 'wagtailadmin_pages:add_subpage'
target_url = reverse(url_name, args=args, kwargs=kwargs)
return target_url
# for every other case - just call the parent method
return super().get_action_url(action, *args, **kwargs)
class CustomPageButtonHelperClass(PageButtonHelper):
add_child_button_classnames = ['add-child'] # can be anything - just setting this to match convention
# add a new button generator that mimics the 'copy_button' from existing code
def add_child_button(self, pk, classnames_add=[], classnames_exclude=[]):
classnames = self.add_child_button_classnames + classnames_add
final_classnames = self.finalise_classname(classnames, classnames_exclude)
return {
# if we wanted - we can skip the creation of CustomPageAdminURLHelper & generate the URL here
# but this may work against reusability later
'url': self.url_helper.get_action_url('add-child', pk), # may need to wrap pk in quote if it could contain non-url-safe chars
'label': 'Add Child',
'classname': final_classnames,
'title': 'Add Child uner this %s' % self.verbose_name
}
# override the PageButtonHelper method to 'add' custom buttons
def get_buttons_for_obj(self, obj, exclude=[], classnames_add=[], classnames_exclude=[]):
# call the parent class method to get the default set of buttons
buttons = super().get_buttons_for_obj(obj, exclude, classnames_add, classnames_exclude)
# set up some variables to do user checks and also get the primary key (id)
permission_helper = self.permission_helper
user = self.request.user
pk = getattr(obj, self.opts.pk.attname)
# many existing permission helpers are already available - see wagtail/contrib/modeladmin/helpers/permission.py
if ('add-child' not in exclude and permission_helper.user_can_create(user)):
# above we follow the convention set up where buttons can be included/excluded easier
# we also do a permissions check
# finally we build the button and add it to the end of the buttons list
add_child_button = self.add_child_button(pk, classnames_add, classnames_exclude)
buttons.append(add_child_button)
return buttons
class CustomAdmin(ModelAdmin):
model = MyPage
menu_label = 'custom ModelAdmin'
button_helper_class = CustomPageButtonHelperClass # added to enable custom button generation
url_helper_class = CustomPageAdminURLHelper # added to enable custom url generation
list_display = ('title', "live")
list_filter = ("date")
search_fields = ("title")
modeladmin_register(CustomAdmin)
代码解释
- https://github.com/wagtail/wagtail/tree/master/wagtail/contrib/modeladmin/helpers - 包含所有助手的代码,这对于理解导入和被覆盖的现有方法很重要。
CustomPageButtonHelperClass
- 通过附加 add_child_button 覆盖
get_buttons_for_obj
。
- 使用现有的权限助手class做一些检查,这将避免需要重写容易出错的用户和授权逻辑
- 调用方法(我们将添加)生成按钮内容,
add_child_button
- 添加方法
add_child_button
- 必须 return 一个带有 url、标签、class 名称和标题的 object。尽量保持现有的约定,其中 class 名称可以 appended/removed 全局
- 最难的是 url 生成,我们将利用 URL 助手的现有结构,但您可以只生成这个 URL in-line.
CustomPageAdminURLHelper
- 覆盖方法
get_action_url
并处理我们关心的特定情况 'action' 是 'add-child'
- 这个方法必须简单地return一个字符串(这将是一个相对的url),最好使用现有的Django系统URL反转。
- 添加 child 页面的 url 名称是
'wagtailadmin_pages:add_subpage'
- 最后用传入的args/kwargs调用Django reverse util,你会在return.
中得到一个漂亮的url
CustomAdmin
- 最后一步是在您的 CustomAdmin 实例上设置这些自定义 url 和按钮助手 classes。
- 这只需要将
button_helper_class
和 url_helper_class
设置为它们各自的帮助程序覆盖。
额外说明和注意事项
- 仔细阅读 ModelAdmin 文档,它们的布局非常好并且很有帮助。 https://docs.wagtail.io/en/stable/reference/contrib/modeladmin/index.html?highlight=modeladmin%20helpers#
- 缺少一些方面,但是代码库中的 helpers 文件夹非常容易阅读,应该可以帮助您确定要定制的代码的流程。
- 这是假设您只想在页面模型上使用这些自定义助手,ModelAdmin 处理页面的方式与其他 objects 之间存在细微差别,您可以进行额外检查,但这取决于您.
- 如果您不关心 class 名称并遵循现有的模型管理约定,您可以简化一些样板代码,这取决于您。
- 这假设您的主键是 URL 安全的,您会在 modeladmin 代码中看到有很多额外的实用程序用法来确保一切 url 安全。
- 创建 child 页面后,用户将返回到 parent 页面的 NON-model 管理列表。更改此设置可能需要一些额外的工作,但上面的代码应该可以满足您的需求。
我正在为每个用户构建管理菜单 w/o 资源管理器视图和自定义 ModelAdmin
个实例。
@hooks.register('construct_main_menu')
def hide_page_explorer_menu_item(request, menu_items):
if request.user.username == 'user1':
menu_items[:] = [item for item in menu_items if item.name not in [
'explorer',
]
]
class CustomAdmin(ModelAdmin):
model = MyPage
menu_label = 'custom ModelAdmin'
list_display = ('title', "live")
list_filter = ("date")
search_fields = ("title")
modeladmin_register(CustomAdmin)
但是生成的列表视图的操作列表(即上下文菜单)缺少资源管理器视图提供的一些功能。
我特别需要"ADD CHILDPAGE"。我知道钩子 register_page_listing_buttons
。但是您只能为资源管理器视图操作列表注册按钮。
是否可以将按钮 "add subpage" 添加到自定义列表视图的操作列表中?
Explorer 列表视图:
自定义 ModelAdmin 列表视图:
回答
ModelAdmin
不使用相同的系统来构建视图中列出的按钮。
相反,它有一个 'helper classes' 的概念,这些用于生成 URLs 和权限检查,这反过来又用于生成出现在各种视图中的按钮。
https://docs.wagtail.io/en/stable/reference/contrib/modeladmin/primer.html?highlight=primer
您将需要在 ModelAdmin
实例上设置一个自定义 button_helper_class,它将在您的 IndexView
中生成您想要的自定义按钮。为此,您需要使用自定义 get_buttons_for_obj
方法导入和扩展 PageButtonHelper
class,该方法将 return 按钮列表。
代码示例
# wagtail_hooks.py
from django.urls import reverse
from wagtail.contrib.modeladmin.options import (ModelAdmin, modeladmin_register)
from wagtail.contrib.modeladmin.helpers import (PageAdminURLHelper, PageButtonHelper)
# MyPage model import not included but will be needed
class CustomPageAdminURLHelper(PageAdminURLHelper):
def get_action_url(self, action, *args, **kwargs):
if action == 'add-child':
# note: add_subpage is used as the internal name for adding child pages
url_name = 'wagtailadmin_pages:add_subpage'
target_url = reverse(url_name, args=args, kwargs=kwargs)
return target_url
# for every other case - just call the parent method
return super().get_action_url(action, *args, **kwargs)
class CustomPageButtonHelperClass(PageButtonHelper):
add_child_button_classnames = ['add-child'] # can be anything - just setting this to match convention
# add a new button generator that mimics the 'copy_button' from existing code
def add_child_button(self, pk, classnames_add=[], classnames_exclude=[]):
classnames = self.add_child_button_classnames + classnames_add
final_classnames = self.finalise_classname(classnames, classnames_exclude)
return {
# if we wanted - we can skip the creation of CustomPageAdminURLHelper & generate the URL here
# but this may work against reusability later
'url': self.url_helper.get_action_url('add-child', pk), # may need to wrap pk in quote if it could contain non-url-safe chars
'label': 'Add Child',
'classname': final_classnames,
'title': 'Add Child uner this %s' % self.verbose_name
}
# override the PageButtonHelper method to 'add' custom buttons
def get_buttons_for_obj(self, obj, exclude=[], classnames_add=[], classnames_exclude=[]):
# call the parent class method to get the default set of buttons
buttons = super().get_buttons_for_obj(obj, exclude, classnames_add, classnames_exclude)
# set up some variables to do user checks and also get the primary key (id)
permission_helper = self.permission_helper
user = self.request.user
pk = getattr(obj, self.opts.pk.attname)
# many existing permission helpers are already available - see wagtail/contrib/modeladmin/helpers/permission.py
if ('add-child' not in exclude and permission_helper.user_can_create(user)):
# above we follow the convention set up where buttons can be included/excluded easier
# we also do a permissions check
# finally we build the button and add it to the end of the buttons list
add_child_button = self.add_child_button(pk, classnames_add, classnames_exclude)
buttons.append(add_child_button)
return buttons
class CustomAdmin(ModelAdmin):
model = MyPage
menu_label = 'custom ModelAdmin'
button_helper_class = CustomPageButtonHelperClass # added to enable custom button generation
url_helper_class = CustomPageAdminURLHelper # added to enable custom url generation
list_display = ('title', "live")
list_filter = ("date")
search_fields = ("title")
modeladmin_register(CustomAdmin)
代码解释
- https://github.com/wagtail/wagtail/tree/master/wagtail/contrib/modeladmin/helpers - 包含所有助手的代码,这对于理解导入和被覆盖的现有方法很重要。
CustomPageButtonHelperClass
- 通过附加 add_child_button 覆盖
get_buttons_for_obj
。 - 使用现有的权限助手class做一些检查,这将避免需要重写容易出错的用户和授权逻辑
- 调用方法(我们将添加)生成按钮内容,
add_child_button
- 添加方法
add_child_button
- 必须 return 一个带有 url、标签、class 名称和标题的 object。尽量保持现有的约定,其中 class 名称可以 appended/removed 全局 - 最难的是 url 生成,我们将利用 URL 助手的现有结构,但您可以只生成这个 URL in-line.
CustomPageAdminURLHelper
- 覆盖方法
get_action_url
并处理我们关心的特定情况 'action' 是'add-child'
- 这个方法必须简单地return一个字符串(这将是一个相对的url),最好使用现有的Django系统URL反转。
- 添加 child 页面的 url 名称是
'wagtailadmin_pages:add_subpage'
- 最后用传入的args/kwargs调用Django reverse util,你会在return. 中得到一个漂亮的url
CustomAdmin
- 最后一步是在您的 CustomAdmin 实例上设置这些自定义 url 和按钮助手 classes。
- 这只需要将
button_helper_class
和url_helper_class
设置为它们各自的帮助程序覆盖。
额外说明和注意事项
- 仔细阅读 ModelAdmin 文档,它们的布局非常好并且很有帮助。 https://docs.wagtail.io/en/stable/reference/contrib/modeladmin/index.html?highlight=modeladmin%20helpers#
- 缺少一些方面,但是代码库中的 helpers 文件夹非常容易阅读,应该可以帮助您确定要定制的代码的流程。
- 这是假设您只想在页面模型上使用这些自定义助手,ModelAdmin 处理页面的方式与其他 objects 之间存在细微差别,您可以进行额外检查,但这取决于您.
- 如果您不关心 class 名称并遵循现有的模型管理约定,您可以简化一些样板代码,这取决于您。
- 这假设您的主键是 URL 安全的,您会在 modeladmin 代码中看到有很多额外的实用程序用法来确保一切 url 安全。
- 创建 child 页面后,用户将返回到 parent 页面的 NON-model 管理列表。更改此设置可能需要一些额外的工作,但上面的代码应该可以满足您的需求。