3

我已经使用 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>

我可以显示所有节点。我想要做的是,基于当前 url 即 /section/News 获取当前级别的所有兄弟姐妹,所有上一级的祖先和下一级的所有相关后代。所以如果我选择新闻我会得到

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

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

我怎样才能做到这一点?任何帮助将非常感激。我正在学习 Django,所以如果很明显我提前道歉。

4

1 回答 1

6

django-page-cms已经解决了这种类型的问题django-mptt,所以我建议看看它在那里完成的方式。

具体来说,渲染树形菜单的模板通过一个名为pages_dynamic_tree_menu.

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

我们可以认为 a Pageindjango-page-cmsSection与您的班级大致相同。

在 99% 的页面之间共享的基本模板中,django-page-cms 让您插入以下代码段

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

pages_navigation 上下文处理器设置(一种将项目添加到 django 项目中所有视图的 模板上下文的方法)并包含顶级页面(即没有父页面的页面)。

标签的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变量。

神奇之处在于语句,它确保仅当页面是当前页面(模板变量由呈现 a 的视图设置)或页面是祖先if时才显示子级。&属性由 提供,该MPTT 的两个属性是父树节点的左值将小于其子节点的左值父节点的右值将大于其右值它的子节点,您可以通过查看SQL 中的树一文中的下图来直观地验证它:current_pagedjango-page-cmsPagelftrghtdjango-mptt

MPTT的图片

通过一些过滤来隐藏未发布的对象的调用get_children_for_frontend()方法,所以没有什么特别的。PageMPTTModel.getChildren()Page

然后标签执行与模板等效的标签,然后再次调用标签,导致整个事情递归:{% include %}pages/dynamic_tree_menu.htmlpages_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 %}

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

于 2012-10-11T05:56:44.873 回答