【问题标题】:How can I render a tree structure (recursive) using a django template?如何使用 django 模板渲染树结构(递归)?
【发布时间】:2010-09-07 02:50:32
【问题描述】:

我在内存中有一个树形结构,我想使用 Django 模板在 HTML 中呈现它。

class Node():
  name = "node name"
  children = []

会有一些对象root 是Node,而children 是Nodes 的列表。 root 会传入模板的内容。

我找到了this 一个关于如何实现这一点的讨论,但发帖者暗示这在生产环境中可能并不好。

有人知道更好的方法吗?

【问题讨论】:

    标签: python django


    【解决方案1】:

    我来晚了。
    你们都使用了这么多不必要的 with 标签,这就是我做递归的方式:

    在“主”模板中:

    <!-- lets say that menu_list is already defined -->
    <ul>
        {% include "menu.html" %}
    </ul>
    

    然后在menu.html:

    {% for menu in menu_list %}
        <li>
            {{ menu.name }}
            {% if menu.submenus|length %}
                <ul>
                    {% include "menu.html" with menu_list=menu.submenus %}
                </ul>
            {% endif %}
        </li>
    {% endfor %}
    

    【讨论】:

    • 恕我直言,这是这个线程中最干净和最好的抽象。好一个亚瑟!
    • 请注意,如果要将 QuerySet 对象传递给模板,则需要在查询集对象上调用 all:{% if menu.submenus.all|length %}
    • 像魅力一样工作。但我想这个解决方案只推出了几年,请参阅the related Django ticket。其他答案已经过时了。
    • 你是救世主!
    • menu.submenus.count 会比这样获取长度更有效吗?
    【解决方案2】:

    纠正这个:

    root_comment.html

    {% extends 'students/base.html' %}
    {% load i18n %}
    {% load static from staticfiles %}
    
    {% block content %}
    
    <ul>
    {% for comment in comments %}
        {% if not comment.parent %}                   ## add this ligic
        {% include "comment/tree_comment.html" %}
        {% endif %}
    {% endfor %}
    </ul>
    
    {% endblock %}
    

    tree_comment.html

    <li>{{ comment.text }}
        {%if comment.children %}
            <ul>
             {% for ch in comment.children.get_queryset %}     # related_name in model
                  {% with comment=ch template_name="comment/tree_comment.html" %}
                       {% include template_name %}
                  {% endwith %}
             {% endfor %}
             </ul>
        {% endif %}
    </li>
    

    例如 - 型号:

    from django.db import models
    from django.contrib.auth.models import User
    from django.utils.translation import ugettext_lazy as _
    
    
    # Create your models here.
    class Comment(models.Model):
        class Meta(object):
            verbose_name = _('Comment')
            verbose_name_plural = _('Comments')
    
        parent = models.ForeignKey(
            'self',
            on_delete=models.CASCADE,
            parent_link=True,
            related_name='children',
            null=True,
            blank=True)
    
        text = models.TextField(
            max_length=2000,
            help_text=_('Please, your Comment'),
            verbose_name=_('Comment'),
            blank=True)
    
        public_date = models.DateTimeField(
            auto_now_add=True)
    
        correct_date = models.DateTimeField(
            auto_now=True)
    
        author = models.ForeignKey(User)
    

    【讨论】:

    • 对包含系统的粗暴滥用,但它有效!我喜欢!它使递归成为可能的事实让我重新思考我的立场,即 djangos 模板并不完整。
    【解决方案3】:

    我有同样的问题,我写了一个模板标签。我知道还有其他类似的标签,但无论如何我都需要学习制作自定义标签:) 我认为结果非常好。

    阅读文档字符串以获取使用说明。

    github.com/skid/django-recurse

    【讨论】:

    • 也许这是正确的链接? skid 的个人资料显示他的姓是 Jordanovski,此项目描述为 a recursive django template tag: github.com/skid/django-recurse
    • 这是完美的解决方案。但是如果我们必须访问循环类别中的其他数据.. 比如:其他信息..
    【解决方案4】:

    使用with模板标签,我可以做树/递归列表。

    示例代码:

    主模板:假设 'all_root_elems' 是一个或多个树根的列表

    <ul>
    {%for node in all_root_elems %} 
        {%include "tree_view_template.html" %}
    {%endfor%}
    </ul>
    

    tree_view_template.html 渲染嵌套的ul、li 并使用node 模板变量如下:

    <li> {{node.name}}
        {%if node.has_childs %}
            <ul>
             {%for ch in node.all_childs %}
                  {%with node=ch template_name="tree_view_template.html" %}
                       {%include template_name%}
                  {%endwith%}
             {%endfor%}
             </ul>
        {%endif%}
    </li>
    

    【讨论】:

    • 虽然我确信有充分的理由不做被问到的事情,但这个答案实际上绕过了这个问题。存在性能损失,但使用 {% with %} 将模板名称存储在变量中可防止 django 模板编译器无限递归。
    • 谢谢!简单,有效。根据数据结构,您甚至可能不需要主文件中的循环(对于根对象)
    【解决方案5】:

    没有人喜欢 dicts 吗?我可能在这里遗漏了一些东西,但这似乎是设置菜单的最自然方式。使用键作为条目,使用值作为链接将其弹出 DIV/NAV 并离开!

    从你的基地

    # Base.html
    <nav>
    {% with dict=contents template="treedict.html" %}
     {% include template %}
    {% endwith %}
    <nav>
    

    叫这个

    # TreeDict.html
    <ul>
    {% for key,val in dict.items %}
     {% if val.items %}
      <li>{{ key }}</li>
      {%with dict=val template="treedict.html" %}
       {%include template%}
      {%endwith%}
     {% else %} 
      <li><a href="{{ val }}">{{ key }}</a></li>
     {% endif %}
    {% endfor %} 
    </ul>
    

    它还没有尝试过默认或有序,也许你有?

    【讨论】:

      【解决方案6】:

      Django 为这个确切的场景提供了一个内置的模板助手:

      https://docs.djangoproject.com/en/dev/ref/templates/builtins/#unordered-list

      【讨论】:

      • 如果您要为每个项目输出的只是“
      • sometext
      • ”,则可以使用。如果您有更复杂项目的嵌套层次结构,并且您(例如)希望每个项目都是一个链接,那么这个标签就没有用了。
      【解决方案7】:

      是的,你可以做到。这是一个小技巧, 将文件名作为变量传递给 {% include %}:

      {% with template_name="file/to_include.html" %}
      {% include template_name %}
      {% endwith %}
      

      【讨论】:

      • 以这种方式嵌套既好又快-我现在正在使用它-尽管我想知道它是否有效(我懒得自己测试了)。任何人都可以加入...
      【解决方案8】:

      这可能比您需要的要多,但是有一个名为“mptt”的 django 模块 - 它在 sql 数据库中存储分层树结构,并包含用于在视图代码中显示的模板。你也许可以在那里找到有用的东西。

      这是链接:django-mptt

      【讨论】:

        【解决方案9】:

        我有一个类似的问题,但是我首先使用 JavaScript 实现了解决方案,然后才考虑如何在 django 模板中做同样的事情。

        我使用序列化器实用程序将模型列表转换为 json,并使用 json 数据作为我的层次结构的基础。

        【讨论】:

          【解决方案10】:

          我认为规范的答案是:“不要”。

          您可能应该做的是解开您的视图代码中的内容,因此只需迭代模板中的(in|de)dents。我想我会通过在树中递归的同时将缩进和缩进添加到列表中,然后将“游记”列表发送到模板来做到这一点。 (然后,模板会从该列表中插入&lt;li&gt; 和&lt;/li&gt;,创建具有“理解”它的递归结构。)

          我也很确定递归地包含模板文件确实是一种错误的方法......

          【讨论】:

          • 我不明白这怎么可能保留原始数据的层次结构,除非您在视图中将整个内容呈现为 HTML。你能提供一个更具体的例子吗?
          • 当然。您制作一个类似 [ 'in', 'in', 'blah', 'out', 'blah', 'out'] 的列表,然后在模板中循环遍历它。如果它等于 'in' 你发出一个 li,'out' 你发出一个 /li 否则你只是转储文本本身。
          • 任何关于为什么递归构建菜单“真的错了”的说明?真的那么贵吗?
          • 虽然我同意分离逻辑/表示。这是出现问题的罕见情况之一。因为它是一个递归的东西被显示。逻辑/表示划分的问题之一是在哪里画线,这样它实际上不会导致过多的耦合,因为它需要控制器中的复杂逻辑才能使简化的视图工作。理论上控制器不应该理解视图,只知道如何传递数据。但我想这只是与现实的妥协之一。
          • 这不应该是公认的答案。创建一个简单的包含模板标签是很简单的,它递归地包含自己以将信息树显示为 html。只要每个递归调用不调用数据库,并且只要实现了适当的缓存,就不会出现任何性能问题。尝试将正确的 html 编写为视图中的连接字符串要麻烦得多; html代码属于模板。
          猜你喜欢
          相关资源
          最近更新 更多
          热门标签