【问题标题】:How to correctly structure a for loop in Django templating language如何在 Django 模板语言中正确构建 for 循环
【发布时间】:2016-04-01 06:23:44
【问题描述】:

我在 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 循环的正确方法是什么

【问题讨论】:

  • 如您在official docs 中所见,语法为{% for var in iterable %}。所以将range(len_values) 作为可迭代对象传递。请注意:传递值列表可能会更好,然后在模板循环中,您可以使用 forloop.counter 访问计数器

标签: python django for-loop django-templates


【解决方案1】:

正如文档清楚显示的那样,您根本无法在 Django 的模板语言中执行此操作。即使您使范围位工作,您的变量查找本身仍然无法工作:venues.i.city 中的i 始终被解释为文字名称“i”。

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

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

模板:

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

【讨论】:

    【解决方案2】:

    正如您在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】:

      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>
      

      【讨论】:

        【解决方案4】:

        Django 模板的设计使其语法尽可能简单。这个想法是,模板是由设计师而不是程序员来实现的。

        在您的情况下,问题在于您不能简单地在 for 标记内添加诸如 range(0, len_values) 之类的 Python 代码。 for 标记需要一个迭代器,它可以由过滤器处理,但不是任意 Python 表达式。

        您有不同的选项来迭代给定的次数:

        • 最简单的方法是更改​​视图,因此您可以将数组本身传递给模板,而不是数组的 len(上下文中有 range(len_values),而不仅仅是 len_values)。
        • 您可以创建自己的模板标签,它可能类似于内置的 for,但需要 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>
        

        【讨论】:

        • 感谢您的回答!我最初得到的 JSON 格式是this,其中每个对象没有像“票证”这样的名称。由于每个对象都没有命名,我还能继续这样做吗?
        • 当然,那么你可能想要这样的东西:render(request, 'my_template.html', context={'tickets': your_json})
        猜你喜欢
        • 2013-04-23
        • 2012-04-12
        • 2013-10-26
        • 1970-01-01
        • 2019-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-25
        相关资源
        最近更新 更多