如何在Django模板中将for循环计数器连接到字符串?

22

我已经在尝试这样拼接字符串:

{% for choice in choice_dict %}
    {% if choice =='2' %}
        {% with "mod"|add:forloop.counter|add:".html" as template %}
            {% include template %}
        {% endwith %}                   
    {% endif %}
{% endfor %}    

但由于某些原因,我只得到了“mod.html”而没有得到forloop.counter的数字。有人知道发生了什么问题以及我该怎么解决吗?非常感谢!


应按照https://dev59.com/X2855IYBdhLWcg3wXTAI的方法工作。 - Narendra Kamma
forloop.counter是整数而不是字符串,我认为这就是问题的原因。 - dting
3个回答

51

你的问题在于for循环计数器是一个整数,而你正在使用add模板过滤器。如果你传递的是所有字符串或者所有整数,这个过滤器会正常工作,但是对于混合类型不行。

解决方法之一是:

{% for x in some_list %}
    {% with y=forloop.counter|stringformat:"s" %}
    {% with template="mod"|add:y|add:".html" %}
        <p>{{ template }}</p>
    {% endwith %}
    {% endwith %}
{% endfor %}

最终的结果是:

<p>mod1.html</p>
<p>mod2.html</p>
<p>mod3.html</p>
<p>mod4.html</p>
<p>mod5.html</p>
<p>mod6.html</p>
...

需要使用带有标签的第二个字符串,因为stringformat标签是通过自动添加%来实现的。 要解决此问题,您可以创建自定义过滤器。 我使用类似于以下内容的代码:

http://djangosnippets.org/snippets/393/

将代码片段保存为 some_app/templatetags/some_name.py

from django import template

register = template.Library()

def format(value, arg):
    """
    Alters default filter "stringformat" to not add the % at the front,
    so the variable can be placed anywhere in the string.
    """
    try:
        if value:
            return (unicode(arg)) % value
        else:
            return u''
    except (ValueError, TypeError):
        return u''
register.filter('format', format)

在模板中:

{% load some_name.py %}

{% for x in some_list %}
    {% with template=forloop.counter|format:"mod%s.html" %}
        <p>{{ template }}</p>
    {% endwith %}
{% endfor %}

@Ethan:这似乎回答了你的问题,不是吗? - Edward Newell
@dting - 这个很好用,除非你使用 forloop.counter0 调用它,否则 if value 这一行会返回 "False" 代表 "0"。为了解决这个问题,只需将该行更改为 if value is not None - trubliphone
值得注意的是,您需要在templatetags目录中添加一个__init__.py文件,并重新启动服务器,以便按照以下方式进行注册:https://docs.djangoproject.com/en/1.10/howto/custom-template-tags/#code-layout - Rikki

3
您可能不想在模板中这样做,这似乎更像是视图的工作:(在for循环中使用if)。
chosen_templates=[]
for choice in choice_dict:
  if choice =='2':
    {% with "mod"|add:forloop.counter|add:".html" as template %}
    template_name = "mod%i.html" %index
    chosen_templates.append(template_name)

然后将chosen_templates传递到您的模板中,您将只有这些模板。
{% for template in chosen_templates %}
  {% load template %}
{% endfor %}

此外,我不太明白为什么您要使用一个字典来选择一个不在字典中的数字作为模板。也许for key,value in dict.items()是您正在寻找的。

3
尝试不使用块"with"。
{% for choice in choice_dict %}
    {% if choice =='2' %}
       {% include "mod"|add:forloop.counter|add:".html" %}                   
    {% endif %}
{% endfor %} 

2
很遗憾,这在Django 1.9上不起作用。 - Wtower

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接