我已经使用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,所以如果很明显我会事先道歉。
答案 0 :(得分:6)
django-page-cms已使用django-mptt
解决了此类问题,因此我建议您查看它在那里所做的工作方式。
具体而言,template to render the tree menu通过名为custom template tag的pages_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)
它的重点是设置page
和children
变量。
魔术在if
语句中,确保仅在页面为当前页面时才显示子项(current_page
模板变量由django-page-cms
视图设置呈现a Page
),或者页面是祖先。 lft
&amp; rght
属性由django-mptt
提供,此MPTT的两个属性是父树节点的左值小于其子节点的左值< / em>和父节点的正确值将超过其子节点的正确值,您可以通过查看文章Trees in SQL中的下图来直观地验证它:
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;模板标记和标记的匹配模板)并应用一些样式,那么您应该能够用这种方法来实现你的目标。