在Wagtail中实现多级自定义菜单

时间:2018-08-07 01:36:19

标签: 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中吗?如果没有,如何实现此多级菜单?也许我从一开始就犯了所有错误?

1 个答案:

答案 0 :(得分:1)

您看过wagtailmenus吗?这样可以节省您一些开发时间和精力。