首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我正在尝试使用django-mptt构建站点导航

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

Stack Overflow用户
提问于 2012-10-11 05:48:19
回答 1查看 1.9K关注 0票数 3

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

代码语言:javascript
复制
[Home]
 [News]
    [Politics][Crime][Policing]  etc 
 then [News] > [Politics]
                 [UKIP][Labour] etc

我相信你已经明白了。我已经创建了部分模型

代码语言:javascript
复制
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()传递到模板中:

代码语言:javascript
复制
<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>

我可以显示所有节点。我想做的是,根据当前的url ie /section/News获取当前级别上的所有兄弟,上一级别上的所有祖先和下一级别上的所有相关后代。所以如果我选择了News,我会得到

代码语言:javascript
复制
[home][**News**][World][Sports][Culture] <- Level 0

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

我该怎么做呢?任何帮助都将不胜感激。我正在学习Django,所以如果很明显的话,我会提前道歉。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-10-11 13:56:45

django-page-cms已经使用django-mptt解决了这类问题,所以我建议您看看它是如何完成的。

具体地说,template to render the tree menu是通过一个名为pages_dynamic_tree_menucustom template tag递归包含的。

这听起来很复杂(自定义的ta-whaaa!),所以我将更详细地分析它。

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

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

代码语言:javascript
复制
<ul>
{% for page in pages_navigation %}
    {% pages_dynamic_tree_menu page %}
{% endfor %}
</ul>

django is set by a context processor (一种在template context中为项目中的所有视图添加项目的方法),并包含顶级页面(即那些没有父级的页面)。

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

代码语言:javascript
复制
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模板变量由呈现Pagedjango-page-cms视图设置),或者页面是祖先页面。lftrght属性是由django-mptt提供的,这个MPTT的两个属性是父树节点的左值将小于其子节点的左值,父节点的右值将大于其子节点的右值,您可以通过查看文章Trees in SQL中的下图来直观地验证这一点

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

然后,标记使用pages/dynamic_tree_menu.html模板执行{% include %}tag equivalent,该模板反过来再次调用pages_dynamic_tree_menu标记,导致整个过程递归:

代码语言:javascript
复制
{% 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 %}

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

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12828949

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档