---
obj: concept
wiki: https://en.wikipedia.org/wiki/Jinja_(template_engine)
website: https://jinja.palletsprojects.com/en/3.1.x
rev: 2024-02-19
---

# Jinja Templates
Jinja is a fast, expressive, extensible templating engine. Special placeholders in the template allow writing code similar to [Python](../dev/programming/languages/Python.md) syntax. Then the template is passed data to render the final document. Jinja template files commonly have the `.j2` extension.

## Syntax
Below is a minimal template that illustrates a few basics using the default Jinja configuration:
```
<!DOCTYPE html>
<html lang="en">
<head>
    <title>My Webpage</title>
</head>
<body>
    <ul id="navigation">
    {% for item in navigation %}
        <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
    {% endfor %}
    </ul>

    <h1>My Webpage</h1>
    {{ a_variable }}

    {# a comment #}
</body>
</html>
```

There are a few kinds of delimiters. The default Jinja delimiters are configured as follows:
- `{% ... %}` for Statements
- `{{ ... }}` for Expressions to print to the template output
- `{# ... #}` for Comments not included in the template output

### Comments
To comment-out part of a line in a template, use the comment syntax which is by default set to `{# ... #}`. This is useful to comment out parts of the template for debugging or to add information for other template designers or yourself:
```
{# note: commented-out template because we no longer use this
    {% for user in users %}
        ...
    {% endfor %}
#}
```

### Expressions
Jinja allows basic expressions everywhere. These work very similarly to regular [Python](../dev/programming/languages/Python.md); even if you’re not working with [Python](../dev/programming/languages/Python.md) you should feel comfortable with it.

#### Literals
The simplest form of expressions are literals. Literals are representations for [Python](../dev/programming/languages/Python.md) objects such as strings and numbers. The following literals exist:

`"Hello World"`

Everything between two double or single quotes is a string. They are useful whenever you need a string in the template (e.g. as arguments to function calls and filters, or just to extend or include a template).

`42` / `123_456`

Integers are whole numbers without a decimal part. The ‘_’ character can be used to separate groups for legibility.

`42.23` / `42.1e2` / `123_456.789`

Floating point numbers can be written using a ‘.’ as a decimal mark. They can also be written in scientific notation with an upper or lower case ‘e’ to indicate the exponent part. The ‘_’ character can be used to separate groups for legibility, but cannot be used in the exponent part.

`['list', 'of', 'objects']`

Everything between two brackets is a list. Lists are useful for storing sequential data to be iterated over. For example, you can easily create a list of links using lists and tuples for (and with) a for loop:

```
<ul>
{% for href, caption in [('index.html', 'Index'), ('about.html', 'About'),
                         ('downloads.html', 'Downloads')] %}
    <li><a href="{{ href }}">{{ caption }}</a></li>
{% endfor %}
</ul>
```

`('tuple', 'of', 'values')`

Tuples are like lists that cannot be modified (“immutable”). If a tuple only has one item, it must be followed by a comma (`('1-tuple',)`). Tuples are usually used to represent items of two or more elements. See the list example above for more details.

`{'dict': 'of', 'key': 'and', 'value': 'pairs'}`

A dict in [Python](../dev/programming/languages/Python.md) is a structure that combines keys and values. Keys must be unique and always have exactly one value. Dicts are rarely used in templates; they are useful in some rare cases such as the `xmlattr()` filter.

`true` / `false`

`true` is always true and `false` is always false.

#### If Expression
It is also possible to use inline if expressions. These are useful in some situations. For example, you can use this to extend from one template if a variable is defined, otherwise from the default layout template:
```
{% extends layout_template if layout_template is defined else 'default.html' %}
```

The general syntax is `<do something> if <something is true> else <do something else>`.

The else part is optional. If not provided, the else block implicitly evaluates into an `Undefined` object (regardless of what `undefined` in the environment is set to):
```
{{ "[{}]".format(page.title) if page.title }}
```

#### Builtin Filters
##### batch(value, linecount: int, fill_with: 'Optional' = None)
A filter that batches items. It works pretty much like slice just the other way round. It returns a list of lists with the given number of items. If you provide a second parameter this is used to fill up missing items. See this example:
```
<table>
{%- for row in items|batch(3, '&nbsp;') %}
  <tr>
  {%- for column in row %}
    <td>{{ column }}</td>
  {%- endfor %}
  </tr>
{%- endfor %}
</table>
```

##### center(value, width: int = 80)
Centers the value in a field of a given width.

##### default(value, default_value, boolean: bool = False)
If the value is undefined it will return the passed default value, otherwise the value of the variable:
```
{{ my_variable|default('my_variable is not defined') }}
```

This will output the value of `my_variable` if the variable was defined, otherwise `'my_variable is not defined'`. If you want to use default with variables that evaluate to false you have to set the second parameter to true:
```
{{ ''|default('the string was empty', true) }}
```

##### dictsort(value, case_sensitive: bool = False, by: Literal\["key", "value"]' = 'key', reverse: bool = False)
Sort a dict and yield (key, value) pairs. [Python](../dev/programming/languages/Python.md) dicts may not be in the order you want to display them in, so sort them first.
```
{% for key, value in mydict|dictsort %}
    sort the dict by key, case insensitive

{% for key, value in mydict|dictsort(reverse=true) %}
    sort the dict by key, case insensitive, reverse order

{% for key, value in mydict|dictsort(true) %}
    sort the dict by key, case sensitive

{% for key, value in mydict|dictsort(false, 'value') %}
    sort the dict by value, case insensitive
```

##### escape(value)
Replace the characters `&`, `<`, `>`, `'`, and `"` in the string with HTML-safe sequences. Use this if you need to display text that might contain such characters in [HTML](../internet/HTML.md).

If the object has an `__html__` method, it is called and the return value is assumed to already be safe for [HTML](../internet/HTML.md).

##### filesizeformat(value, binary: bool = False)
Format the value like a ‘human-readable’ file size (i.e. 13 kB, 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega, Giga, etc.), if the second parameter is set to True the binary prefixes are used (Mebi, Gibi).

##### first(seq)
Return the first item of a sequence.

##### float(value, default: float = 0.0)
Convert the value into a floating point number. If the conversion doesn’t work it will return `0.0`. You can override this default using the first parameter.

##### forceescape(value)
Enforce [HTML](../internet/HTML.md) escaping. This will probably double escape variables.

##### format(value, args...)
Apply the given values to a printf-style format string, like string % values.
```
{{ "%s, %s!"|format(greeting, name) }}
Hello, World!
```

In most cases it should be more convenient and efficient to use the `%` operator or `str.format()`.
```
{{ "%s, %s!" % (greeting, name) }}
{{ "{}, {}!".format(greeting, name) }}
```

##### groupby(value, attribute: str | int, default: Any | None = None, case_sensitive: bool = False)
Group a sequence of objects by an attribute using [Python](../dev/programming/languages/Python.md)’s `itertools.groupby()`. The attribute can use dot notation for nested access, like `"address.city"`. Unlike [Python](../dev/programming/languages/Python.md)’s `groupby`, the values are sorted first so only one group is returned for each unique value.

For example, a list of `User` objects with a `city` attribute can be rendered in groups. In this example, `grouper` refers to the `city` value of the group.
```
<ul>{% for city, items in users|groupby("city") %}
  <li>{{ city }}
    <ul>{% for user in items %}
      <li>{{ user.name }}
    {% endfor %}</ul>
  </li>
{% endfor %}</ul>
```

`groupby` yields namedtuples of `(grouper, list)`, which can be used instead of the tuple unpacking above. `grouper` is the value of the attribute, and `list` is the items with that value.
```
<ul>{% for group in users|groupby("city") %}
  <li>{{ group.grouper }}: {{ group.list|join(", ") }}
{% endfor %}</ul>
```

You can specify a `default` value to use if an object in the list does not have the given attribute.
```
<ul>{% for city, items in users|groupby("city", default="NY") %}
  <li>{{ city }}: {{ items|map(attribute="name")|join(", ") }}</li>
{% endfor %}</ul>
```

##### indent(s: str, width: int | str = 4, first: bool = False, blank: bool = False)
Return a copy of the string with each line indented by 4 spaces. The first line and blank lines are not indented by default.

Parameters:
- **width** – Number of spaces, or a string, to indent by.
- **first** – Don’t skip indenting the first line.
- **blank** – Don’t skip indenting empty lines.

##### items(value)
Return an iterator over the `(key, value)` items of a mapping.

`x|items` is the same as `x.items()`, except if `x` is undefined an empty iterator is returned.

This filter is useful if you expect the template to be rendered with an implementation of Jinja in another programming language that does not have a `.items()` method on its mapping type.
```
<dl>
{% for key, value in my_dict|items %}
    <dt>{{ key }}
    <dd>{{ value }}
{% endfor %}
</dl>
```

##### join(value, d: str = '', attribute: str | int | NoneType = None)
Return a string which is the concatenation of the strings in the sequence. The separator between elements is an empty string per default, you can define it with the optional parameter:
```
{{ [1, 2, 3]|join('|') }}
    -> 1|2|3

{{ [1, 2, 3]|join }}
    -> 123
```

##### last(seq)
Return the last item of a sequence.

##### length(obj)
Return the number of items in a container.

##### max(value)
Return the largest item from the sequence.
```
{{ [1, 2, 3]|max }}
    -> 3
```

##### min(value)
Return the smallest item from the sequence.
```
{{ [1, 2, 3]|min }}
    -> 1
```

##### random(seq)
Return a random item from the sequence.

##### replace(s: str, old: str, new: str, count: int | None = None)
Return a copy of the value with all occurrences of a substring replaced with a new one. The first argument is the substring that should be replaced, the second is the replacement string. If the optional third argument `count` is given, only the first `count` occurrences are replaced:
```
{{ "Hello World"|replace("Hello", "Goodbye") }}
    -> Goodbye World

{{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
    -> d'oh, d'oh, aaargh
```

##### reverse(value)
Reverse the object or return an iterator that iterates over it the other way round.

##### round(value: float, precision: int = 0, method: Literal\["common", "ceil", "floor"]' = 'common')
Round the number to a given precision. The first parameter specifies the precision (default is `0`), the second the rounding method:
- `'common'` rounds either up or down
- `'ceil'` always rounds up
- `'floor'` always rounds down

If you don’t specify a method `'common'` is used.
```
{{ 42.55|round }}
    -> 43.0
{{ 42.55|round(1, 'floor') }}
    -> 42.5
```

Note that even if rounded to 0 precision, a float is returned. If you need a real integer, pipe it through int:
```
{{ 42.55|round|int }}
    -> 43
```

##### trim(value)
Strip leading and trailing characters, by default whitespace.

##### truncate(s: str, length: int = 255, killwords: bool = False, end: str = '...', leeway: int | None = None)
Return a truncated copy of the string. The length is specified with the first parameter which defaults to `255`. If the second parameter is `true` the filter will cut the text at length. Otherwise it will discard the last word. If the text was in fact truncated it will append an ellipsis sign (`"..."`). If you want a different ellipsis sign than `"..."` you can specify it using the third parameter. Strings that only exceed the length by the tolerance margin given in the fourth parameter will not be truncated.
```
{{ "foo bar baz qux"|truncate(9) }}
    -> "foo..."
{{ "foo bar baz qux"|truncate(9, True) }}
    -> "foo ba..."
{{ "foo bar baz qux"|truncate(11) }}
    -> "foo bar baz qux"
{{ "foo bar baz qux"|truncate(11, False, '...', 0) }}
    -> "foo bar..."
```

##### unique(value, case_sensitive: bool = False, attribute: str | int | NoneType = None)
Returns a list of unique items from the given iterable.
```
{{ ['foo', 'bar', 'foobar', 'FooBar']|unique|list }}
    -> ['foo', 'bar', 'foobar']
```

The unique items are yielded in the same order as their first occurrence in the iterable passed to the filter.

Parameters:
- **case_sensitive** – Treat upper and lower case strings as distinct.
- **attribute** – Filter objects with unique values for this attribute.

##### urlencode(value)
Quote data for use in a URL path or query using UTF-8.

Basic wrapper around urllib.parse.quote() when given a string, or urllib.parse.urlencode() for a dict or iterable.

##### urlize(value)
Convert URLs in text into clickable links.

This may not recognize links in some situations. Usually, a more comprehensive formatter, such as a [Markdown](../files/Markdown.md) library, is a better choice.

##### wordcount(s: str)
Count the words in that string.

##### wordwrap(s: str, width: int = 79, break_long_words: bool = True, wrapstring: str | None = None, break_on_hyphens: bool = True)
Wrap a string to the given width. Existing newlines are treated as paragraphs to be wrapped separately.

Parameters:
- **s** – Original text to wrap.
- **width** – Maximum length of wrapped lines.
- **break_long_words** – If a word is longer than `width`, break it across lines.
- **break_on_hyphens** – If a word contains hyphens, it may be split across lines.
- **wrapstring** – String to join each wrapped line. Defaults to `Environment.newline_sequence`.

#### Builtin Tests
##### boolean(value)
Return true if the object is a boolean value.

##### defined(value)
Return true if the variable is defined:
```
{% if variable is defined %}
    value of variable: {{ variable }}
{% else %}
    variable is not defined
{% endif %}
```

See the `default()` filter for a simple way to set undefined variables.

##### divisibleby(value, num: int)
Check if a variable is divisible by a number.

##### even(value)
Return true if the variable is even.

##### in(value, seq)
Check if `value` is in `seq`.

##### odd(value)
Return true if the variable is odd.

### Statements
#### for
Loop over each item in a sequence. For example, to display a list of users provided in a variable called users:
```
<h1>Members</h1>
<ul>
{% for user in users %}
  <li>{{ user.username }}</li>
{% endfor %}
</ul>
```

Inside of a for-loop block, you can access some special variables:

| Variable           | Description                                                                             |
| ------------------ | --------------------------------------------------------------------------------------- |
| loop.index         | The current iteration of the loop. (1 indexed)                                          | 
| loop.index0        | The current iteration of the loop. (0 indexed)                                          |
| loop.revindex      | The number of iterations from the end of the loop (1 indexed)                           |
| loop.revindex0     | The number of iterations from the end of the loop (0 indexed)                           |
| loop.first         | True if first iteration.                                                                |
| loop.last          | True if last iteration.                                                                 |
| loop.length        | The number of items in the sequence.                                                    |
| loop.cycle         | A helper function to cycle between a list of sequences. See the explanation below.      |
| loop.depth         | Indicates how deep in a recursive loop the rendering currently is. Starts at level 1    |
| loop.depth0        | Indicates how deep in a recursive loop the rendering currently is. Starts at level 0    |
| 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).                |

Within a for-loop, it’s possible to cycle among a list of strings/variables each time through the loop by using the special loop.cycle helper:
```
{% for row in rows %}
    <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}
```

#### if
The if statement in Jinja is comparable with the [Python](../dev/programming/languages/Python.md) if statement. In the simplest form, you can use it to test if a variable is defined, not empty and not false:
```
{% if kenny.sick %}
    Kenny is sick.
{% elif kenny.dead %}
    You killed Kenny!  You bastard!!!
{% else %}
    Kenny looks okay --- so far
{% endif %}
```

#### include
The `include` tag renders another template and outputs the result into the current template.
```
{% include 'header.html' %}
Body goes here.
{% include 'footer.html' %}
```