树结构(自身的外键)和模板

时间:2017-11-01 09:14:00

标签: django django-templates foreign-keys

我有类别的树结构。具有引用自身的外键的类别。

class Category(MetaData):
    parent = models.ForeignKey('self', blank=True, null=True, verbose_name='parent category', on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    description = models.TextField()

因为我不知道类别树的深度(不能用于),我需要使用递归函数:

def cat_for_parents(self, cat_obj):
                ...
                if cat_obj.parent_id:
                        p = cat_obj.parent
                        ...
                        self.cat_for_parents(p)

但是我如何在模板中实现这个函数来获得这样的东西(理论上无限递归循环):

<ul>
 <li>CategoryA
  <ul>
   <li>SubCategA1
     <ul>
       <li> Subcateg Subcateg B1
         <ul>
            <li> Subcateg SubCateg C1>
             <li> Subcateg SubCateg C2>
         <ul>
         <li> Subcateg Subcateg B2>
         ............. 

1 个答案:

答案 0 :(得分:1)

我用inclusion_tag解决了这个问题。

示例:

model

#just add related_name:
parent = models.ForeignKey('self', blank=True, null=True, related_name='subs', on_delete=models.CASCADE)

views.py

categories = Category.objects.filter(parent=None)
# then pass it to template

template

<ul>
    {% for category in categories %}
        <li>
            {{ category.name }}
            {% if category.parent.count > 0 %}
                {% tree_structure category %}
            {% endif %}
        </li>
    {% endfor %}
</ul>

自定义标记功能:

@register.inclusion_tag('path/to/tree_structure.html')
def tree_structure(category):
    subs = category.subs.all()
    return {"subs": subs}

tree_structure.html

# remember to load your custom tags file
<ul>
    {% for sub in subs %}
        <li>
            {{ sub.name }}
            {% if sub.parent.count > 0 %}
                {% tree_structure sub %}
            {% endif %}
        </li>
    {% endfor %}
</ul>

工作原理:

获取没有任何父级的类别并将其发送到模板。 在模板中,我们使用for循环逐个呈现类别,然后在转到下一个类别进行渲染之前,检查该类别是否具有任何subs。 如果该类别有任何子类,您将把类别传递给自定义模板标记,然后您将获得该给定类别的所有子类别,并将其传递给另一个模板文件以呈现它们,但在完成之前,请检查该类别类别,以查看是否有一个子类别,如果它只是在你完成渲染第一个之前再次调用自定义函数。它将持续到没有更多的类别和子类别,并在最后传递一个完整的模板,其中包含第一个传递的类别的所有子类别到主模板,以便在其他类别之前呈现。

我自己无法测试此代码,因此可能存在小问题。

另请查看自定义模板标记的文档: Custom template tags and filters