使用索引页面子链接创建Django Wagtail边栏

时间:2016-06-29 00:54:49

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

我正在使用Django Wagtail构建网站,并且无法确定如何添加侧栏菜单,该菜单将列出父索引页面的所有子页面。例如,我有一个standard_index_page.html,我在管理员中创建了一个父页面,然后我使用standard_page.html模板添加了子页面。

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

{% standard_index_listing calling_page=self %}

并显示包含链接的所有子页面,但我也想显示子页面上所有子链接的列表。

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

1 个答案:

答案 0 :(得分:9)

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

许多前端框架不允许多级菜单,因为有些人认为它超出了最佳实践范围。但是,对于像SmartMenus这样的库,您可以使用一点肘部油脂来显示这种结构。

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

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

以下是我们要做的事情:

  • 创建一些获取网站根目录的模板标记 当前站点遍历站点根目录的直接子项遍历任何较低级别的子项,而循环遍历当前menuitem的子项在每个级别发现时

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

  • {% 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的navbar类构建的,并根据我的需求进行了定制。只需根据您的需求定制这些。整个菜单构建过程由{% top_menu_children %}调用,因此请将此标记放在您希望呈现菜单的基本模板中。更改top_menu.html以反映菜单的整体结构以及如何呈现每个menuitem。更改children_items.html以反映您希望所有顶级菜单项的子项在任何深度呈现的方式。

<强> my_site /标签/ 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 /标签/ 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>

现在,在您的基本级别模板中(假设您正在使用其中一个;如果没有,请转到它:))您可以遍历菜单,同时将杂乱清除清除到您{{1 }}秒。

<强> my_site / base.html文件

inclusion_tag

我写了一篇关于此事的博客文章 - check it out了解更多细节。或者,转到Thermaline.com以查看它的实际情况,但我认为现在还没有多个级别的深度。如果有,他们将自动呈现:)

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

您需要做的就是:

  • 在基本模板中加入<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>
  • 致电demo_tags您希望呈现菜单的地方。
  • 自定义{% top_menu %}top_menu.html以呈现 首先,然后是所有后续级别的页面。

向Tivix喊出他们的post on two-level menus,这对我来说是一个很好的起点!