如何在Django模板语言中正确构造for循环

时间:2015-12-26 22:44:48

标签: python django for-loop django-templates

我在Django应用程序中有一个模板文件,它使用模板变量来使用相应视图中的数据。在视图的上下文中(在呈现页面时返回),我有一个名为len_values的变量,用于存储循环结束范围的值。我目前使用这种语法构建了for循环:

 <ul class= 'list-group'>
     {% for i in range(0,len_values) %}
         <li  class = 'list-group-item' >
             Artist: {{form_artistSelect}}
             Location: {{venues.i.city}}, {{venues.i.region}}
             Venue: {{venues.i.name}}
             Date: {{dates.i}}
             tickets status: {{ticket_statuses.i}}<br>
             <a href = {{ticket_urls.i}}> ticket link </a>
             {% if user.is_authenticated %}
                 <button id = 'invite' type='button' class= 'btn btn-info btn-lg' data-toggle = 'modal' data-target='#myModal' venue={{venues.i}} date={{dates.i}} ticket_url={{ticket_urls.i}} artist = {{form_artistSelect}}> Invite a friend </button>
                 <button id = 'save' type = 'button' class = 'btn btn-primary-outline'> Save Concert </button>
             {% endif %}
         </li>
     {% endfor %}
 </ul>

当我尝试使用此代码时,我收到错误:Could not parse the remainder: '(0,len_values)' from 'range(0,len_values)'

我见过this old SO post似乎正在解决类似的问题,但基于赞成票没有确定的答案,所提供的答案都是陈旧的。

在Django模板格式

中构造for循环的正确方法是什么

4 个答案:

答案 0 :(得分:1)

您无法在Django的模板语言中执行此操作,因为文档清楚地显示了这一点。即使你让范围位工作,你的变量查找本身仍然不起作用:i中的venues.i.city始终被解释为文字名称“i”。

但是你无论如何都不想这样做:即使在原始的Python中也不应该这样做。你永远不会迭代范围(len(某事)); 总是遍历事物本身。这里也是如此:在你看来,你应该创建一个数据结构 - 比如一个dicts列表 - 包含按项目分组的城市,地区,日期,状态等,然后在你的模板中迭代:

data = [
    {'city': "City 1", "region": "Region 1", "date": date_1, ....},
    ...
]

模板:

{% for item in data %}
    Location: {{ item.city }}, {{ item.region }}
    ...
{% endfor %}

答案 1 :(得分:1)

Django模板的设计使它的语法尽可能简单。我们的想法是模板由设计人员而不是程序员实现。

在您的情况下,问题是您无法在for标记内添加范围(0,len_values)等Python代码。 for标记需要一个迭代器,它可以由过滤器处理,但不是任意的Python表达式。

您可以使用不同的选项来迭代给定次数:

  • 最简单的方法是更改​​视图,因此不是数组的len,而是将数组本身传递给模板(在上下文中有范围(len_values),而不仅仅是len_values)。
  • 你可以创建自己的模板标签,它可以类似于内置的,但期望len而不是迭代器。
  • 您可以使用Jinja2,它在语法上与Django模板非常相似,但您在模板语法方面并不局限(不确定在这种情况下您的代码是否可行)。

但在你的情况下,我认为问题是另一个问题,在视图方面。不是为场地,日期,ticket_statuses等设置不同的迭代器,而是只有一个具有相同的长度,你应该只有一个包含所有信息。

所以,而不是像这样的观点:

def my_view(request):
    context = {'venues': ['venue 1', 'venue 2', 'venue 3'],
               'dates': ['date 1', 'date 2', 'date 2'],
               'ticket_statuses': ['status 1', 'status 2', 'status 3']}
    render(request, 'my_template.html', context)

你应该有类似的东西:

def my_view(request):
    context = {'tickets': [
                  {'venue': 'venue 1', 'date': 'date 1', 'status': 'status 1'},
                  {'venue': 'venue 2', 'date': 'date 2', 'status': 'status 2'},
                  {'venue': 'venue 3', 'date': 'date 3', 'status': 'status 3'}]}
    render(request, 'my_template.html', context)

然后,您的模板将如下所示:

<ul class= 'list-group'>
     {% for ticket in tickets  %}
         <li  class = 'list-group-item' >
             Artist: {{form_artistSelect}}
             Location: {{ticket.venue.city}}, {{ticket.venue.region}}
             Venue: {{ticket.venue.name}}
             Date: {{ticket.date}}
             tickets status: {{ticket.status}}<br>
             <a href = {{ticket.url}}> ticket link </a>
             {% if user.is_authenticated %}
                 <button id = 'invite' type='button' class= 'btn btn-info btn-lg' data-toggle = 'modal' data-target='#myModal' venue={{venues.i}} date={{dates.i}} ticket_url={{ticket_urls.i}} artist = {{form_artistSelect}}> Invite a friend </button>
                 <button id = 'save' type = 'button' class = 'btn btn-primary-outline'> Save Concert </button>
             {% endif %}
         </li>
     {% endfor %}
 </ul>

答案 2 :(得分:1)

正如您在official docs中看到的那样,语法是

{% for var in iterable %}

因此在视图中传递range(len_values)作为可迭代的上下文。

请注意:在不计算其长度的情况下,传递值列表会好得多。

如果你需要每个项目的索引,你可以在模板循环中使用forloop.counter访问它(如果从零开始则使用forloop.counter0),例如

{% for item in data %}
    This is item number {{ forloop.counter }}
    {{ item.city }}
    {{ item.region }}
{% endfor %}

答案 3 :(得分:1)

Django模板标签不是python代码。你不能在这里使用功能。但是你可以像在python中一样,使用for循环迭代迭代。

第二件不起作用的是:

Location: {{venues.i.city}}, {{venues.i.region}}

我不会在这里被视为变量,而是作为场地的名称。

正确的解决方案是:

 <ul class= 'list-group'>
     {% for venue in venues %}
         <li  class = 'list-group-item' >
             Artist: {{form_artistSelect}}
             Location: {{venue.city}}, {{venue.region}}
             Venue: {{venue.name}}
             Date: {{dates.i}}
            ... etc ...
         </li>
     {% endfor %}
 </ul>

但是存在问题:您尝试在多个列表中使用该变量。 Django模板默认不允许这样做,所以你有3个选项......

1。将列表连接到一个您将迭代的列表中。

这是首选解决方案,因为准备数据应该进入您的视图。

2。创建自己的模板标签或过滤器

您可以使用某些自定义模板标记或过滤器从其他列表中提取数据。然后只需遍历其中一个列表并将forloop.counter或forloop.counter0传递给自定义标记以提取特定数据。

3。使用脏黑客

有一种方法可以解决django模板的这种限制,但它真的很脏,你不应该使用它。这是一个例子:

<ul class= 'list-group'>
     {% for venue in venues %}{% with index=forloop.counter0|stringformat:"i"|add:":" %}{% with date=dates|slice:index ticket_status=ticket_statuses|slice:index ticket_url=ticket_urls|slice:index %}
         <li  class = 'list-group-item' >
             Artist: {{form_artistSelect}}
             Location: {{venue.city}}, {{venue.region}}
             Venue: {{venue.name}}
             Date: {{date.0}}
             tickets status: {{ticket_status.0}}<br>
             <a href = {{ticket_url.0}}> ticket link </a>
             {% if user.is_authenticated %}
                 <button id = 'invite' type='button' class= 'btn btn-info btn-lg' data-toggle = 'modal' data-target='#myModal' venue={{venue}} date={{date.0}} ticket_url={{ticket_url.0}} artist = {{form_artistSelect}}> Invite a friend </button>
                 <button id = 'save' type = 'button' class = 'btn btn-primary-outline'> Save Concert </button>
             {% endif %}
         </li>
     {% endwith %}{% endwith %}{% endfor %}
 </ul>