Skip to main content

Loops

Loops let you repeat a section of your template for each item in a list. This is essential for line items, tables, product lists, and any repeating content.

Simple loop

{
"products": ["Apple Juice", "Orange Juice", "Pineapple Juice"]
}
<ul>
{% for product in products %}
<li>{{ product }}</li>
{% endfor %}
</ul>

Output:

<ul>
<li>Apple Juice</li>
<li>Orange Juice</li>
<li>Pineapple Juice</li>
</ul>

Looping over objects

When your list contains objects (dictionaries), you can access their properties:

{
"items": [
{"name": "Widget A", "price": "$10.00"},
{"name": "Widget B", "price": "$25.00"},
{"name": "Widget C", "price": "$15.00"}
]
}
<table>
<thead>
<tr>
<th>Item</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td>{{ item.name }}</td>
<td>{{ item.price }}</td>
</tr>
{% endfor %}
</tbody>
</table>

Nested loops

You can nest loops for more complex data structures:

{
"departments": [
{
"name": "Engineering",
"members": ["Alice", "Bob"]
},
{
"name": "Design",
"members": ["Carol", "Dave"]
}
]
}
{% for dept in departments %}
<h3>{{ dept.name }}</h3>
<ul>
{% for member in dept.members %}
<li>{{ member }}</li>
{% endfor %}
</ul>
{% endfor %}

Loop variables

Inside a {% for %} loop, Jinja2 gives you some useful built-in variables:

VariableDescription
loop.indexCurrent iteration (1-based)
loop.index0Current iteration (0-based)
loop.firstTrue if this is the first iteration
loop.lastTrue if this is the last iteration
loop.lengthTotal number of items
{% for item in items %}
<tr class="{% if loop.last %}last-row{% endif %}">
<td>{{ loop.index }}</td>
<td>{{ item.name }}</td>
</tr>
{% endfor %}

Iterating over key-value pairs

To loop over a dictionary's keys and values:

{
"fruit": [
{"key": 1, "value": "Apple"},
{"key": 2, "value": "Banana"},
{"key": 3, "value": "Orange"}
]
}
{% for item in fruit %}
{% for key, value in item.items() %}
{{key}}: {{value}}
{% endfor %}
{% endfor %}

Next steps