Django模板遍历嵌套列表

时间:2022-02-24 13:00:19

In Django, how do we iterate over lists in template for something like [[1,[2,[3]],[4,[]]],[2,[3]]].

在Django中,我们如何迭代模板中的列表以获得类似于[[1,[2,[3]],[4,[]],[2,[3]]的内容。

Please note that the above is just a random example. Each element of list can have any number of nested lists further inside. I would like to iterate through each and every value inside and also have an idea of what is the parent so that we can appropriately style the HTML.

请注意以上只是一个随机的例子。列表的每个元素都可以有任意数量的嵌套列表。我想遍历其中的每个值,并对父元素有一个概念,这样我们就可以对HTML进行适当的样式化。

Although there is one way to generate HTML in the view itself by recursion and use the corresponding variable in template, this makes the django template and view dependent which is not desired(loose coupling principle). One example of using views is here but a representation in template system itself would be better than this type of implementation.

尽管有一种方法可以通过递归在视图本身中生成HTML并在模板中使用相应的变量,但这使得django模板和视图依赖于不需要的东西(松耦合原则)。使用视图的一个例子在这里,但是模板系统本身中的表示将比这种类型的实现更好。

2 个解决方案

#1


1  

Django template is not designed to handle complex logics.
For example, you can't write nested logic by using include tag like this:

Django模板不是设计用来处理复杂逻辑的。例如,不能通过使用这样的include标记来编写嵌套逻辑:

# foo.html
{% if nodes|iterable %}
<ul>
{% for x in nodes %}
  {% include "foo.html" with nodes=x %}
{% endfor %}
</ul>
{% else %}
<li>{{ nodes }}</li>
{% endif %}

Because Django template nodes get parsed and compiled before they get rendered, and the compiling of the above code could fall into loops and fail by hitting maximum recursion depth.

因为Django模板节点在被呈现之前会被解析和编译,因此上面代码的编译可能会陷入循环,并通过最大递归深度失败。

Normally, a template tag just like {% nested nodes %}, which works like a view but belongs to the scope of Django template, is all you need.

通常,您只需要一个模板标记,就像{%嵌套的节点%},它与视图类似,但属于Django模板的范围。

Moreover, you could transform the data to a flat one through a filter, then loop over it easily:

此外,您可以通过过滤器将数据转换为扁平的数据,然后轻松地对其进行循环:

{% for x in nodes|nested_to_flat %}
{% if x.start_nodes %}<ul>{% endif %}
{% if x.end_nodes %}</ul>{% endif %}
{% if x.start_node %}<li>{% endif %}
{% if x.end_node %}</li>{% endif %}
{% if x.is_data %}{{ x.data }}{% endif %}
{% endfor %}

# nested_to_flat
@register.filter
def nested_to_flat(nodes):
    if isinstance(nodes, list):
        yield {'start_nodes': True}
        for node in nodes:
            yield {'start_node': True}
            for i in nested_to_flat(node):
                yield i
            yield {'end_node': True}
        yield {'end_nodes': True}
    else:
        yield {'data': nodes, 'is_data': True}

This is similar to the idea of rendering a mptt tree or threaded comments.

这类似于呈现mptt树或线程注释的想法。

#2


0  

As mentioned in the above comments django-mptt is a premade solution, which should fit your problem quite good.

正如上面评论中提到的,django-mptt是一个预先制定的解决方案,它应该非常适合您的问题。

If you want to roll you own template tags, you can have a look at custom template tags in the django documentation.

如果您希望滚动自己的模板标记,可以查看django文档中的自定义模板标记。

Some hints:

一些提示:

  • By creating markup with unlimited nesting you might run into usability problems because screen real estate is limited and probably want to consider limiting the depth of the data structure for this reason. If you have to stick with your data structure, you can use for loops in the template according to the number of levels.
  • 通过创建具有无限嵌套的标记,您可能会遇到可用性问题,因为屏幕空间有限,因此可能需要考虑限制数据结构的深度。如果必须坚持使用数据结构,可以根据级别的数量在模板中使用for循环。
  • If you prefer the built-in template tags, you will be much better of using a list of nested dictionaries (containing lists wherever order is important), which also will be easier to read in the template.
  • 如果您更喜欢内置的模板标记,那么您将会更好地使用嵌套字典列表(在任何顺序重要的地方都包含列表),这也将更容易在模板中读取。
  • Loose coupling is fine as a general principle. But as the views main purpose in Django is to prepare the data structure for the template, you can't decouple it totally.
  • 松耦合作为一个通用的原则是很好的。但由于Django的视图主要目的是为模板准备数据结构,所以不能完全解耦。

#1


1  

Django template is not designed to handle complex logics.
For example, you can't write nested logic by using include tag like this:

Django模板不是设计用来处理复杂逻辑的。例如,不能通过使用这样的include标记来编写嵌套逻辑:

# foo.html
{% if nodes|iterable %}
<ul>
{% for x in nodes %}
  {% include "foo.html" with nodes=x %}
{% endfor %}
</ul>
{% else %}
<li>{{ nodes }}</li>
{% endif %}

Because Django template nodes get parsed and compiled before they get rendered, and the compiling of the above code could fall into loops and fail by hitting maximum recursion depth.

因为Django模板节点在被呈现之前会被解析和编译,因此上面代码的编译可能会陷入循环,并通过最大递归深度失败。

Normally, a template tag just like {% nested nodes %}, which works like a view but belongs to the scope of Django template, is all you need.

通常,您只需要一个模板标记,就像{%嵌套的节点%},它与视图类似,但属于Django模板的范围。

Moreover, you could transform the data to a flat one through a filter, then loop over it easily:

此外,您可以通过过滤器将数据转换为扁平的数据,然后轻松地对其进行循环:

{% for x in nodes|nested_to_flat %}
{% if x.start_nodes %}<ul>{% endif %}
{% if x.end_nodes %}</ul>{% endif %}
{% if x.start_node %}<li>{% endif %}
{% if x.end_node %}</li>{% endif %}
{% if x.is_data %}{{ x.data }}{% endif %}
{% endfor %}

# nested_to_flat
@register.filter
def nested_to_flat(nodes):
    if isinstance(nodes, list):
        yield {'start_nodes': True}
        for node in nodes:
            yield {'start_node': True}
            for i in nested_to_flat(node):
                yield i
            yield {'end_node': True}
        yield {'end_nodes': True}
    else:
        yield {'data': nodes, 'is_data': True}

This is similar to the idea of rendering a mptt tree or threaded comments.

这类似于呈现mptt树或线程注释的想法。

#2


0  

As mentioned in the above comments django-mptt is a premade solution, which should fit your problem quite good.

正如上面评论中提到的,django-mptt是一个预先制定的解决方案,它应该非常适合您的问题。

If you want to roll you own template tags, you can have a look at custom template tags in the django documentation.

如果您希望滚动自己的模板标记,可以查看django文档中的自定义模板标记。

Some hints:

一些提示:

  • By creating markup with unlimited nesting you might run into usability problems because screen real estate is limited and probably want to consider limiting the depth of the data structure for this reason. If you have to stick with your data structure, you can use for loops in the template according to the number of levels.
  • 通过创建具有无限嵌套的标记,您可能会遇到可用性问题,因为屏幕空间有限,因此可能需要考虑限制数据结构的深度。如果必须坚持使用数据结构,可以根据级别的数量在模板中使用for循环。
  • If you prefer the built-in template tags, you will be much better of using a list of nested dictionaries (containing lists wherever order is important), which also will be easier to read in the template.
  • 如果您更喜欢内置的模板标记,那么您将会更好地使用嵌套字典列表(在任何顺序重要的地方都包含列表),这也将更容易在模板中读取。
  • Loose coupling is fine as a general principle. But as the views main purpose in Django is to prepare the data structure for the template, you can't decouple it totally.
  • 松耦合作为一个通用的原则是很好的。但由于Django的视图主要目的是为模板准备数据结构,所以不能完全解耦。