How can I concatenate forloop.counter to a string in my django template

14,428

Solution 1

Your problem is that the forloop.counter is an integer and you are using the add template filter which will behave properly if you pass it all strings or all integers, but not a mix.

One way to work around this is:

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

which results in:

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

The second with tag is required because stringformat tag is implemented with an automatically prepended %. To get around this you can create a custom filter. I use something similar to this:

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

save the snipped as 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)

in template:

{% load some_name.py %}

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

Solution 2

Try without using the block "with"

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

Solution 3

You probably don't want to do this in your templates, this seems more like a views job: (use of if within a for loop).

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)

Then pass chosen_templates to your template where you will have only

{% for template in chosen_templates %}
  {% load template %}
{% endfor %}

Also, I don't quite understand why you are using a dict to select the template with a number that is not in the dictionnary. for key,value in dict.items() may be what you are looking for.

Share:
14,428
Ethan
Author by

Ethan

Updated on June 03, 2022

Comments

  • Ethan
    Ethan almost 2 years

    I am already trying to concatenate like this:

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

    but for some reason I am only getting "mod.html" and not the forloop.counter number. Does anyone have any idea what is going on and what I can do to fix this issue? Thanks alot!

  • Edward Newell
    Edward Newell almost 10 years
    @Ethan: this seems to answer your question doesn't it?
  • Wtower
    Wtower over 8 years
    NIce, unfortunately this doesn't work with Django 1.9.
  • trubliphone
    trubliphone about 8 years
    @dting - This works great, unless you call it with forloop.counter0, in which case the if value line will return "False" for "0". To get around this, just change that line to if value is not None.
  • Rikki
    Rikki about 7 years
    Worth noting that you need a init.py in the templatetags directory, and to restart the server, for this to register, as per: docs.djangoproject.com/en/1.10/howto/custom-template-tags/…