在Django模板中将For循环迭代作为列表索引

3 投票
3 回答
2721 浏览
提问于 2025-04-17 10:38

我正在搭建一个django网页,但遇到了一些问题,就是我不知道怎么在模板中使用for循环的当前迭代来处理多个列表。

        {% for num in loopRange %}
    <tr>
        {% for num2 in subRange %}
        <td>{% cycle list1 list2 list3 list4 %}</td>
        {% endfor %}
    </tr>
    {% endfor %}

我在stackoverflow上找到了一些类似的问题,尝试使用cycle这个功能,但结果是每次都打印出列表中的所有成员——这其实并不意外,但我就是搞不明白该怎么做。

我有多个内容相似的列表,每个列表都是一行中的一列。所以,如果用python来拼接字符串的话,大概就是这个样子:

for i in xrange(5):
    string = list1[i] + list2[i] + list3[i] + list 4[i]

基本上就是这样。我把每个列表作为上下文传入,还有两个xranges(在第一个例子中是loopRange和Subrange),我需要五行(每个列表有五个成员)和四列(四个列表)。

补充:简单来说,我想用列表的索引来引用,比如foo[bar],在django中是用foo.bar来表示,但bar显然不能是一个整数,也不能作为内容传入一个可迭代的范围。

谢谢!

3 个回答

0

如果你真的想在模板里做这个,有一些原因的话,你可以写一个自定义模板标签来帮你实现:

#app/templatetags/zip.py
from django import template

register = template.Library()

class Zipper(template.Node):
    def __init__(self, format_string, var_name):
        self.format_string = format_string
        self.var_name = var_name
    def render(self, context):
        zippables = [context[tok] for tok in self.format_string.split()]
        import pdb; pdb.set_trace()
        context[self.var_name] = zip(*zippables)
        return ''

import re

@register.tag(name="zip")
def do_zip(parser, token):
    try:
        # Splitting by None == splitting by spaces.
        tag_name, arg = token.contents.split(None, 1)
    except ValueError:
        raise template.TemplateSyntaxError("%r tag requires arguments" % token.contents.split()[0])
    m = re.search(r'(.*?) as (\w+)', arg)
    if not m:
        raise template.TemplateSyntaxError("%r tag had invalid arguments" % tag_name)
    format_string, var_name = m.groups()
    return Zipper(format_string, var_name)

注意:在Django 1.4中,这种写法会变得简单很多,因为新增了assignment_tag

然后,你可以这样使用它:

{%load zip%}

{% zip list1 list2 list3 list4 as list_of_rows %}

你可以在那个代码块里随意使用list_of_rows,包括在两个嵌套的循环里面。

1

你可以简单地创建一个过滤器,从列表中返回一个项目:

@register.filter
def get_item(row, i):
    try:
        return row[i]
    except IndexError:
        return ''

然后:

{{ list1|get_item:num2 }}
3

我认为最好的方法是在把数据传给模板之前,先在视图中处理好这些数据。

比如,可以使用内置的 zip 函数来根据包含列的列表创建行的列表:

rows = zip(list1, list2, list3, list4)

之后,模板可以逐行遍历这些行,如果需要的话,可以通过索引来访问列:

{% for row in rows %}
  {{row.0}} {{row.1}} {{row.2}} {{row.3}}
{% endfor %}

撰写回答