Loops

💡
Learn how to use Jinja loops to generate dynamic content. This is the fourth article in our series on Jinja templating.

Jinja's for loops enable you to iterate over data structures such as lists, dictionaries, and tuples, to produce dynamic content. For instance, you can use a loop to generate a list of blog posts on a website or display the names of all team members on a company page.

Here is an example of Jinja loop that iterates over a list of customers named customers:


{% for customer in customers %}
	{{ customer.name }}
{% endfor %}

As with conditionals, you need to explicitly mark the end of the loop block, in this case using endfor.

Loop over dictionaries

If you are iterating over a dictionary, you need to use a slightly different syntax


{% for key, value in my_dict.items() %}
	{{ key }} = {{ value }}
{% endfor %}

Use an else statement

You can optionally also add an else statement to the loop: that statement will be used if the data structure you are iterating over is empty. For example:


{% for customer in customers %}
	{{ customer.name }}
{% else %}
	No customer.
{% endfor %}

Use loop-specific variables

Jinja provides several loop-specific variables that are available within your loop block: an example is loop.first, which is True if your loop is iterating over its first element and False in every other case. Here is a practical example:


# file: jinja-templates/03-loops.txt

{%- for customer in customers -%}
	{% if not loop.first %},{% endif %}{{ customer.name -}}
{% endfor %}

This template will print all customer names in a single line, prepending each of them with a comma with the exception of the first one.

Rendering the template with the following input


>>> tpl = env.get_template("03-loops.txt")
>>> tpl.render(customers=[{"name": "A"}, {"name": "B"}, {"name": "C"}])

produces


A,B,C

A does not have a leading comma because not loop.first returned False, since A is the first element in the list.

Avoiding unwanted commas is especially useful when using loops to build an SQL query with a dynamic list of columns. For example, the following template generates a valid SQL query, without extra trailing commas:

{% set values = [ 'Central','South','East','West'] %}
SELECT
{% for value in values %}
	'{{value}}' as {{ value }} 
    {% if not loop.last %},{% endif %}
{% endfor %}

Here is an overview of the loop-specific variables, while the complete list is available here:

Variable

Description

loop.index

The current iteration of the loop. (1 indexed)

loop.revindex

The number of iterations from the end of the loop (1 indexed)

loop.first

True if first iteration.

loop.last

True if last iteration.

loop.length

The number of items in the sequence.

loop.cycle

Cycle through a given list of strings or variables. E.g.: {{ loop.cycle('odd', 'even') }}

loop.previtem

The item from the previous iteration of the loop. Undefined during the first iteration.

loop.nextitem

The item from the following iteration of the loop. Undefined during the last iteration.

loop.changed(*val)

True if previously called with a different value (or not called at all).

Filter elements

You can use an if statement to filter the sequence during iteration, allowing you to skip those elements (if any) that do not meet the condition.

For example:


{% for customer in customers if customer.is_business %}
	{{ customer.name }}
{% else %}
	No customer.
{% endfor %}

will only return the names of those customers for which is_business == True.

Just like with regular conditional statements, you can combine multiple conditions using logical operators.


References

- https://jinja.palletsprojects.com/en/3.1.x/templates/#for