【问题标题】:Creating Django Wagtail Sidebar with Index Page Child Links使用索引页面子链接创建 Django Wagtail 侧边栏
【发布时间】:2016-10-31 12:16:52
【问题描述】:

我正在使用 Django Wagtail 构建一个站点,但无法弄清楚如何添加一个侧边栏菜单,该菜单将列出父索引页面的所有子页面。例如,我有一个 standard_index_page.html,我用它在 Admin 中创建了一个父页面,然后我使用 standard_page.html 模板添加了它的子页面。

在我的standard_index_page.html 模板中,我有以下代码

{% standard_index_listing calling_page=self %}

它会显示所有带有链接的子页面,但我还想在子页面上显示所有子链接的列表。

我希望这是有道理的,有人可以伸出援手。谢谢。

【问题讨论】:

    标签: django django-models django-templates django-views wagtail


    【解决方案1】:

    本质上,您遍历了由Django-Treebeard 提供给 Wagtail 的页面层次结构的树结构。

    许多前端框架不允许使用多级菜单,因为有些人认为这超出了最佳实践。但是,使用诸如SmartMenus 之类的库,您可以用一点肘油来显示这个结构。

    根据我的需要,没有简单的解决方案。所以,虽然我想分享一个例子来说明我是如何做到这一点的,但它可能缺少解释。如果您有任何问题,我很乐意为您解答。

    我为此苦苦挣扎了一段时间,虽然可能有更简单的方法来遍历树,但随着需求的扩大,我构建了以下方法。它允许我们遍历站点中的所有活动页面,检查当前页面何时在菜单中呈现,并允许对呈现进行细粒度控制。

    这是我们要做的:

    • 创建一些模板标签,这些标签将获取网站的根目录 当前站点遍历站点根目录的直接子级遍历任何较低级别的子级,同时遍历当前菜单项的子级在每个级别发现时

    在您的基本模板中,这意味着我们需要:

    • {% load demo_tags %} 导入我们的自定义模板标签
    • 调用{% top_menu calling_page=self %}获取并渲染所有 站点根目录的直接子节点。这些项目将显示在标准菜单栏上。
    • 在模板内调用{% top_menu_children parent=menuitem %}{% top_menu %} 渲染以获取并渲染所有第二和 较低级别的子页面。这包括将鼠标悬停在父菜单项上时要显示的所有菜单项。

    这是我创建的自定义 demo_tags.py 文件,用于遍历页面层次结构的所有级别。这样做的好处是它不需要提供任何自定义上下文数据;它与 Wagtail 一起开箱即用!

    @register.assignment_tag(takes_context=True)
    def get_site_root(context):
        ''' 
        Returns a core.Page, not the implementation-specific model used
        so object-comparison to self will return false as objects would differ  
        '''
        return context['request'].site.root_page
    
    
    def has_menu_children(page):
        '''
        Returns boolean of whether children pages exist to the page supplied
        '''   
        return page.get_children().live().in_menu().exists()    
    
    
    @register.inclusion_tag('info_site/tags/top_menu.html', takes_context=True)
    def top_menu(context, parent, calling_page=None):
        '''
        Retrieves the top menu items - the immediate children of the parent page
        The has_menu_children method is necessary in many cases. For example, a bootstrap menu requires
        a dropdown class to be applied to a parent
        '''
        root = get_site_root(context)
        try:
            is_root_page = (root.id == calling_page.id)
        except:
            is_root_page = False
    
        menuitems = parent.get_children().filter(
            live=True,
            show_in_menus=True
        ).order_by('title')
    
        for menuitem in menuitems:
            menuitem.show_dropdown = has_menu_children(menuitem)
    
        return {
            'calling_page': calling_page,
            'menuitems': menuitems,
            'is_root_page':is_root_page,
            # required by the pageurl tag that we want to use within this template
            'request': context['request'],
        }
    
    
    @register.inclusion_tag('my_site/tags/top_menu_children.html', takes_context=True)
    def top_menu_children(context, parent, sub=False, level=0):
        ''' Retrieves the children of the top menu items for the drop downs '''
        menuitems_children = parent.get_children().order_by('title')
        menuitems_children = menuitems_children.live().in_menu()
    
        for menuitem in menuitems_children:
            menuitem.show_dropdown = has_menu_children(menuitem)
    
        levelstr= "".join('a' for i in range(level)) # for indentation
        level += 1
    
        return {
            'parent': parent,
            'menuitems_children': menuitems_children,
            'sub': sub,
            'level':level,
            'levelstr':levelstr,
            # required by the pageurl tag that we want to use within this template
            'request': context['request'],
        }
    

    本质上,页面呈现三个层次:

    • 站点根目录由{% get_site_root %}调用
    • 一级子由{% top_menu %}调用
    • 二级和更低级别的子级由{% top_menu_children %} 调用,每当菜单中显示的页面有子级在呈现此标记时时都会调用它。

    为了做到这一点,我们需要创建要由我们的top_menutop_menu_children 模板标签呈现的模板。

    请注意 - 这些都是为 Bootstrap 3 的导航栏类构建的,并根据我的需要进行了定制。只需根据您的需要定制这些。整个菜单构建过程由{% top_menu_children %} 调用,因此将此标记放置在您希望呈现菜单的基本模板中。更改top_menu.html 以反映菜单的整体结构以及如何呈现每个menuitem。更改children_items.html 以反映您希望如何呈现所有顶级菜单项的子项,在任何深度。

    my_site/tags/top_menu.html

    {% load demo_tags wagtailcore_tags static %}
    {% get_site_root as site_root %}
    
    {# FOR TOP-LEVEL CHILDREN OF SITE ROOT; In a nav or sidebar, these are the menu items we'd generally show before hovering. #}
    
    <div class="container">
        <div class="collapse navbar-collapse" id="navbar-collapse-3">
            <ul class="nav navbar-nav navbar-left">
                {% for menuitem in menuitems %}
                    <li class="{% if menuitem.active %}active{% endif %}">
                        {% if menuitem.show_dropdown %}
                            <a href="{{ menuitem.url }}">{{ menuitem.title }}
                                <span class="hidden-lg hidden-md hidden-sm visible-xs-inline">
                                    <span class="glyphicon glyphicon-chevron-right"></span>
                                </span>
                            </a>
                            {% top_menu_children parent=menuitem %}
                        {% else %}
                            <a href="{% pageurl menuitem %}">{{ menuitem.title }}</a>
                        {% endif %}
                    </li>
                {% endfor %}
            </ul>
        </div>
    </div>
    

    my_site/tags/children_items.html

    {% load demo_tags wagtailcore_tags %}
    
    {# For second- and lower-level decendents of site root; These are items not shown prior to hovering on their parent menuitem, hence the separate templates (and template tags) #}
    
    <ul class="dropdown-menu">
        {% for child in menuitems_children %}
            {% if child.show_dropdown %}
                <li>
                    <a href="{% pageurl child %}">
                        {% for i in levelstr %}&nbsp&nbsp{% endfor %}
                        {{ child.title }}
                        <span class="glyphicon glyphicon-chevron-right"></span>
                    </a>
                    {# On the next line, we're calling the same template tag we're rendering. We only do this when there are child pages of the menu item being rendered. #}
                    {% top_menu_children parent=child sub=True level=level %}
                    {# ^^^^ SmartMenus is made to render menus with as many levels as we like. Bootstrap considers this outside of best practices and, with version 3, has deprecated the ability to do so. Best practices are made to be broken, right :] #}
                </li>
            {% else %}
                <li>
                    <a href="{% pageurl child %}">
                        <!-- Allows for indentation based on depth of page in the site structure -->
                        {% for i in levelstr %}&nbsp&nbsp{% endfor %}
                        {{ child.title }}
                    </a>
                </li>
            {% endif %}
        {% endfor %}
    </ul>
    

    现在,在您的基本级别模板中(假设您正在使用一个;如果没有,请使用它 :))您可以遍历菜单,同时清除 inclusion_tags 使用的模板的混乱。

    my_site/base.html

    <ul class="nav navbar-nav navbar-left">
        {% for menuitem in menuitems %}
            <li class="{% if menuitem.active %}active{% endif %}">
                {% if menuitem.show_dropdown %}
                    <a href="{{ menuitem.url }}">{{ menuitem.title }}
                        <span class="hidden-lg hidden-md hidden-sm visible-xs-inline">
                            <span class="glyphicon glyphicon-chevron-right"></span>
                        </span>
                    </a>
                    {% top_menu_children parent=menuitem %}
                {% else %}
                    <a href="{% pageurl menuitem %}">{{ menuitem.title }}</a>
                {% endif %}
            </li>
        {% endfor %}
    </ul>
    

    我写了一篇关于此的博客文章 - check it out 了解更多详细信息。或者,前往Thermaline.com 看看它的实际效果,尽管我认为现在还没有多层次的深度。如果有,它们会自动呈现:)

    现在,这个示例是针对导航栏的,但它可以很容易地适用于侧边栏。

    你需要做的就是:

    • 在基本模板中包含 demo_tags
    • 致电{% top_menu %},在您希望呈现菜单的地方。
    • 自定义top_menu.htmlchildren_items.html来渲染 首先是所有后续级别的页面。

    感谢 Tivix 的 post on two-level menus,这对我来说是一个很好的起点!

    【讨论】:

    • 哇,多么棒的帖子啊!! :) 我过去曾多次查看过您的网站。在回复之前,我需要消化并尝试所有这些。感谢您的宝贵时间。
    • 非常酷,很高兴听到!我一直想更积极地发帖,听到有读者的消息真是令人振奋:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多