我正在尝试使用django-mptt构建网站导航

时间:2012-10-10 21:48:19

标签: django django-mptt

我已经使用django-mptt对我想要存储我的文章的标题的部分和子部分等进行建模。有些部分和部分会有孩子,有些则不会。  例如:

[Home]
 [News]
    [Politics][Crime][Policing]  etc 
 then [News] > [Politics]
                 [UKIP][Labour] etc

我相信你明白了。 我创建了Section模型

class Section(MPTTModel):
    name = models.CharField(max_length=50)
    parent = TreeForeignKey('self',null=True, blank=True, related_name='sub_sections')
    tree = SectionTreeManager()

并将Section.objects.all()传递给模板: -

<ul class="headernav" >

    {% recursetree sections %}

        <li>
            <a href="/section/{{node.name}}" >{{ node.name }}</a>

             {% if node.is_leaf_node %}
                <ul  class="headernav"> 
                    {{ children }}
                </ul>
            {% endif %}
           </li>
    {% endrecursetree %}
</ul>

我可以显示所有节点。我想要做的是,根据当前网址即/ section / News  让当前级别的所有兄弟姐妹获得前一级别的所有祖先以及所有相关后代的级别。所以,如果我选择了新闻,我会得到

[home][**News**][World][Sports][Culture] <- Level 0

[Politics][Crime][Education] <- Children on Level 1

我该怎么做?任何帮助将非常感激。我正在学习Django,所以如果很明显我会事先道歉。

1 个答案:

答案 0 :(得分:6)

django-page-cms已使用django-mptt解决了此类问题,因此我建议您查看它在那里所做的工作方式。

具体而言,template to render the tree menu通过名为custom template tagpages_dynamic_tree_menu递归包含。

这听起来很复杂(自定义ta-whaaa!),所以我会把它分解一下。

我们可以认为Page in django-page-cms与您的Section类大致相同。

在99%的网页之间共享的基本模板中,django-page-cms gets you to insert the following snippet

<ul>
{% for page in pages_navigation %}
    {% pages_dynamic_tree_menu page %}
{% endfor %}
</ul>

pages_navigation is set by一个context processor(为django项目中的所有视图添加项目template context的方法)并包含顶级页面(即没有父母)。

pages_dynamic_tree_menu标签的定义和注册如下:

def pages_dynamic_tree_menu(context, page, url='/'):
    """
    Render a "dynamic" tree menu, with all nodes expanded which are either
    ancestors or the current page itself.

    Override ``pages/dynamic_tree_menu.html`` if you want to change the
    design.

    :param page: the current page
    :param url: not used anymore
    """
    lang = context.get('lang', pages_settings.PAGE_DEFAULT_LANGUAGE)
    page = get_page_from_string_or_id(page, lang)
    children = None
    if page and 'current_page' in context:
        current_page = context['current_page']
        # if this node is expanded, we also have to render its children
        # a node is expanded if it is the current node or one of its ancestors
        if(page.tree_id == current_page.tree_id and
            page.lft <= current_page.lft and
            page.rght >= current_page.rght):
            children = page.get_children_for_frontend()
    context.update({'children': children, 'page': page})
    return context
    pages_dynamic_tree_menu = register.inclusion_tag(
        'pages/dynamic_tree_menu.html',
        takes_context=True
    )(pages_dynamic_tree_menu)

它的重点是设置pagechildren变量。

魔术在if语句中,确保仅在页面为当前页面时才显示子项(current_page模板变量由django-page-cms视图设置呈现a Page),或者页面是祖先。 lft&amp; rght属性由django-mptt提供,此MPTT的两个属性是父树节点的左值小于其子节点的左值< / em>和父节点的正确值将超过其子节点的正确值,您可以通过查看文章Trees in SQL中的下图来直观地验证它:

picture of MPTT

get_children_for_frontend() Page方法调用MPTTModel.getChildren()并进行一些过滤以隐藏未发布的Page个对象,因此没有什么特别之处。

然后,代码会使用tag equivalent模板执行{% include %}pages/dynamic_tree_menu.html,{{3}}模板会再次调用pages_dynamic_tree_menu标记,从而导致整个内容递归:

{% load pages_tags cache %}
{% if page.calculated_status %}
<li {% ifequal page current_page %}class="selected"{% endifequal %}>
<a href="{% show_absolute_url page %}">{% show_content page "title" %}</a>
{% if children %}
    <ul>{% for child in children %}{% pages_dynamic_tree_menu child url %}{% endfor %}</ul>
{% endif %}
</li>
{% endif %}

因此,如果您定义了类似的设置(为模板提供顶级部分和当前部分,请定义&#34;包含&#34;模板标记和标记的匹配模板)并应用一些样式,那么您应该能够用这种方法来实现你的目标。