wagtail - 在 Wagtail 中实现多级自定义菜单
问题描述
我正在努力增强我的网站目前正在使用的单级菜单,效果很好。代码如下(去掉了不相关的部分):
from wagtail.contrib.settings.models import BaseSetting
from modelcluster.models import ClusterableModel
class AbstractCustomMenuItem(models.Model):
"""
Derive from this model to define one or more CustomMenus.
"""
url = models.CharField('URL', max_length=200, blank=True,
help_text='This must be either a fully qualified URL, e.g. https://www.google.com or a local absolute URL, '
'e.g. /admin/login'
)
page = models.ForeignKey('wagtailcore.Page', null=True, blank=True, on_delete=models.CASCADE, related_name='+',
help_text='If a Page is selected, the URL field is ignored. The title of the selected Page will be displayed '
'if the Link Text field is blank.'
)
link_text = models.CharField('Link Text', max_length=50, blank=True)
is_separator = models.BooleanField( 'Separator', default=False,
help_text='Separators are used to visually distinguish different sections of a menu.'
)
panels = [
MultiFieldPanel([
FieldPanel('url', classname='col8 url'), FieldPanel('link_text', classname='col4 link-text'),
], classname='url-and-link-text'),
# This is a bit gnarly, but it was the best way I could find to render the form in a pretty
# way. I'm using MultiFieldPanel and classname='col8' entirely for formatting, rather than organization.
MultiFieldPanel([PageChooserPanel('page')], classname='col8 page-chooser'),
MultiFieldPanel([FieldPanel('is_separator', classname='separator')]),
]
class Meta:
abstract = True
@register_setting(order=1000)
class Settings(BaseSetting, ClusterableModel):
####### FIELD CODE #######
...
####### FORM CODE #######
...
theme_and_menu_panels = [
InlinePanel( 'header_menu_items', label='Header Menu Item',
help_text='You can optionally add a Header Menu to your site, which will appear in the ribbon at the top '
'of the page.'
),
InlinePanel('footer_menu_items', label='Footer Menu Item',
help_text='You can optionally add a Footer Menu to your site, which will appear in the footer.'
),
]
...
edit_handler = TabbedInterface(
[
...
ObjectList(theme_and_menu_panels, heading='Theme and Menus', classname='theme-and-menus'),
...
]
)
class HeaderMenuItem(Orderable, AbstractCustomMenuItem):
"""
This class provides the model for the Header Menu Items that can be added to a Site's settings.
"""
settings = ParentalKey('www.Settings', related_name='header_menu_items', on_delete=models.CASCADE)
class FooterMenuItem(Orderable, AbstractCustomMenuItem):
"""
This class provides the model for the Footer Menu Items that can be added to a Site's settings.
"""
settings = ParentalKey('www.Settings', related_name='footer_menu_items', on_delete=models.CASCADE)
这使我的代码能够分配单独的自定义页眉和页脚菜单。
但是,现在我需要升级此代码以允许标题菜单项可以选择在其下方拥有自己的子菜单。而且我认为我可以做与我最初创建 MenuItems 时所做的基本相同的事情,并且只是将它们放在HeaderMenuItem
类的下面,而不是下面Settings
。
所以我改变了HeaderMenuItem
课程,并补充说HeaderMenuDropdownItem
:
class HeaderMenuItem(Orderable, ClusterableModel, AbstractCustomMenuItem):
"""
This class provides the model for the Header Menu Items that can be added to a Site's settings.
"""
settings = ParentalKey('www.Settings', related_name='header_menu_items', on_delete=models.CASCADE)
panels = [
MultiFieldPanel([
FieldPanel('url', classname='col8 url'), FieldPanel('link_text', classname='col4 link-text'),
], classname='url-and-link-text'),
# This is a bit gnarly, but it was the best way I could find to render the form in a pretty
# way. I'm using MultiFieldPanel and classname='col8' entirely for formatting, rather than organization.
MultiFieldPanel([PageChooserPanel('page')], classname='col8 page-chooser'),
MultiFieldPanel([FieldPanel('is_separator', classname='separator')]),
InlinePanel('dropdown_items', classname='dropdown-items'),
]
class HeaderMenuDropdownItem(Orderable, AbstractCustomMenuItem):
"""
This class provides the model for the Header Menu Dropdown items.
"""
header_menu_item = ParentalKey('www.HeaderMenuItem', related_name='dropdown_items', on_delete=models.CASCADE)
不幸的是,当我加载 Wagtail 管理页面以编辑 Settings 类时,现在出现以下异常:
File "/.../django/core/handlers/exception.py" in inner
35. response = get_response(request)
File "/.../django/core/handlers/base.py" in _get_response
128. response = self.process_exception_by_middleware(e, request)
File "/.../django/core/handlers/base.py" in _get_response
126. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/.../django/views/decorators/cache.py" in _cache_controlled
31. response = viewfunc(request, *args, **kw)
File "/.../wagtail/admin/urls/__init__.py" in wrapper
102. return view_func(request, *args, **kwargs)
File "/.../wagtail/admin/decorators.py" in decorated_view
34. return view_func(request, *args, **kwargs)
File "/.../wagtail/contrib/settings/views.py" in edit
83. instance=instance, form=form, request=request)
File "/.../wagtail/admin/edit_handlers.py" in bind_to_instance
152. new.on_instance_bound()
File "/.../wagtail/admin/edit_handlers.py" in on_instance_bound
294. request=self.request))
File "/.../wagtail/admin/edit_handlers.py" in bind_to_instance
152. new.on_instance_bound()
File "/.../wagtail/admin/edit_handlers.py" in on_instance_bound
294. request=self.request))
File "/.../wagtail/admin/edit_handlers.py" in bind_to_instance
152. new.on_instance_bound()
File "/.../wagtail/admin/edit_handlers.py" in on_instance_bound
708. request=self.request))
File "/.../wagtail/admin/edit_handlers.py" in bind_to_instance
152. new.on_instance_bound()
File "/.../wagtail/admin/edit_handlers.py" in on_instance_bound
294. request=self.request))
File "/.../wagtail/admin/edit_handlers.py" in bind_to_instance
152. new.on_instance_bound()
File "/.../wagtail/admin/edit_handlers.py" in on_instance_bound
693. self.formset = self.form.formsets[self.relation_name]
Exception Type: AttributeError at /admin/settings/www/settings/3/
Exception Value: 'HeaderMenuItemForm' object has no attribute 'formsets'
我究竟做错了什么?ParentalKey 可以简单地不嵌套在另一个 ParentalKey 中吗?如果没有,我该如何实现这个多级菜单?也许我从一开始就错了?
解决方案
你看过wagtailmenus吗?它可能会为您节省一些开发时间和精力。
推荐阅读
- extjs - 未触发侦听器事件
- android - Camera preview on surface view continuos flow
- arduino - Quectel BG96 MQTT 发布错误
- java - 如何在比较数组列表时删除空格
- c# - 在 Winforms 中绘制图像
- java - 如何恢复 Fragment 中 AdapterViewFlipper 的状态?
- python - 使用 OpenCV 和 python 在较大的图像中裁剪灰度图像
- ionic3 - 我该如何解决这个问题?在移动设备上安装离子应用程序时,我不断收到此信息
- relational-database - 基于其他关系从关系中选择
- azure - 如何从在 AD B2C 中注册的 WebApp 调用在 Azure AD 刀片(在 ADB2C 租户内)中注册的 WebAPI?