django模板中父子关系的树结构

时间:2011-03-08 07:17:19

标签: django treeview django-templates

如何在不使用django-mptt的情况下在django模板中实现树结构。

我有模特。

class Person(TimeStampedModel):
    name  = models.CharField(max_length=32)
    parent      = models.ForeignKey('self', null=True, blank=True, related_name='children')

现在我想要..

 Parent
    Child 1
         subchild 1.1
         subchild 1.2
             nextsubchild 1.2.1
    Child 2
    Child 3

应该点击名称以显示他们的个人资料。

4 个答案:

答案 0 :(得分:11)

我刚刚完成了这个。我想要一个子导航的树结构,但我不想对递归模板做任何奇怪的事情。

我实现的解决方案非常简单:我只是简单地在视图中递归(在我的例子中是一个通用的辅助函数),并将层次结构展平为一个简单的列表。然后,在我的模板中,我只使用for循环迭代列表。

列表中的每个元素可以是以下三种内容之一:“in”,对象或“out”。在我的例子中,我在视图中构建了一系列ul li元素,所以当我遇到“in”时,我会创建一个新的ul,当我遇到“out”时,我会关闭ul。否则,我渲染项目。

我的模板代码如下所示:

                          {% for item in sub_nav %}     
                                {% if item == "in" %}         
                                    <ul>   
                                {% else %}                    
                                    {% if item == "out" %}            
                                            </ul>                 
                                        </li>                 
                                    {% else %}                    

                                            <li>                          
                                                <a href='{{item.full_url}}'>{{item.name}}</a>
                                                {% if item.leaf %}        
                                                </li>                     
                                                {% endif %}           

                                    {% endif %}           
                                {% endif %}           
                            {% endfor %}   

辅助函数中的代码如下所示:

def get_category_nav(request,categories=None):
"""Recursively build a list of product categories. The resulting list is meant to be iterated over in a view"""
if categories==None:
    #get the root categories
    categories = ProductCategory.objects.filter(parent=None)
    categories[0].active=True
else:
    yield 'in'

for category in categories:
    yield category
    subcats = ProductCategory.objects.select_related().filter(parent=category)
    if len(subcats):
        category.leaf=False
        for x in get_category_nav(request,subcats):
            yield x
    else:
        category.leaf=True
yield 'out'

使用这些代码段,您应该能够构建任何类型的分层树,而无需在模板中进行任何递归,并将所有逻辑保留在视图中。

我知道已经有一个已接受的答案,但我想我会发布这项技术,以防它帮助其他人。

答案 1 :(得分:10)

来自Django while loop问题和

http://docs.djangoproject.com/en/dev/howto/custom-template-tags/#inclusion-tags

# view.py

@register.inclusion_tag('children.html')
def children_tag(person):
    children = person.children.all()
    return {'children': children}

# children.html

<ul>
    {% for child in children %}
    <li> <a href="{{ child.get_absolute_url }}">{{ child }}</a></li>
        {% if child.children.count > 0 %}
        {% children_list child %}
        {% endif %}
    {% endfor %}
</ul>


# your template

{% children_tag parent %}

答案 2 :(得分:3)

这些都是很好的答案,但我巩固了一点,并把它放在实际模型上。

class RecursiveThing(models.Model):

    name = models.CharField(max_length=32)
    parent = models.ForeignKey('self', related_name='children', blank=True, null=True)

    def as_tree(self):
        children = list(self.children.all())
        branch = bool(children)
        yield branch, self
        for child in children:
            for next in child.as_tree():
                yield next
        yield branch, None

然后在你的模板中:

<ul>
    {% for thing in things %}
        {% for branch, obj in thing.as_tree %}
            {% if obj %}
                <li>{{ obj.name }}
                {% if branch %}
                    <ul>
                {% else %}
                    </li>
                {% endif %}
            {% else %}
                {% if branch %}
                    </ul>
                {% endif %}
            {% endif %}
        {% endfor %}
    {% endfor %}
</ul>

答案 3 :(得分:0)

这很简单

您在视图中所要做的就是获取所有对象:

people = Person.objects.all()

然后在你的模板中:

{% for person in people %}
  <li>- {{person.name}} </li>
  {% for child in person.children.all %}
     <ul>* {{child.nom}} </ul>
  {% endfor %}
 </li>          
{% endfor %}