If you have used a different template engine in the past and want to switch to Jinja2 here is a small guide that shows the basic syntactic and semantic changes between some common, similar text template engines for Python.
Jinja2 is mostly compatible with Jinja1 in terms of API usage and template syntax. The differences between Jinja1 and 2 are explained in the following list.
Jinja2 has mostly the same syntax as Jinja1. What’s different is that macros require parentheses around the argument list now.
Additionally Jinja2 allows dynamic inheritance now and dynamic includes. The old helper function rendertemplate is gone now, include can be used instead. Includes no longer import macros and variable assignments, for that the new import tag is used. This concept is explained in the Import documentation.
Another small change happened in the for-tag. The special loop variable doesn’t have a parent attribute, instead you have to alias the loop yourself. See Accessing the parent Loop for more details.
If you have previously worked with Django templates, you should find Jinja2 very familiar. In fact, most of the syntax elements look and work the same.
However, Jinja2 provides some more syntax elements covered in the documentation and some work a bit different.
This section covers the template changes. As the API is fundamentally different we won’t cover it here.
In Django method calls work implicitly, while Jinja requires the explicit Python syntax. Thus this Django code:
{% for page in user.get_created_pages %}
...
{% endfor %}
...looks like this in Jinja:
{% for page in user.get_created_pages() %}
...
{% endfor %}
This allows you to pass variables to the method, which is not possible in Django. This syntax is also used for macros.
In Django you can use the following constructs to check for equality:
{% ifequal foo "bar" %}
...
{% else %}
...
{% endifequal %}
In Jinja2 you can use the normal if statement in combination with operators:
{% if foo == 'bar' %}
...
{% else %}
...
{% endif %}
You can also have multiple elif branches in your template:
{% if something %}
...
{% elif otherthing %}
...
{% elif foothing %}
...
{% else %}
...
{% endif %}
Jinja2 provides more than one argument for filters. Also the syntax for argument passing is different. A template that looks like this in Django:
{{ items|join:", " }}
looks like this in Jinja2:
{{ items|join(', ') }}
It is a bit more verbose, but it allows different types of arguments - including variables - and more than one of them.
In addition to filters there also are tests you can perform using the is operator. Here are some examples:
{% if user.user_id is odd %}
{{ user.username|e }} is odd
{% else %}
hmm. {{ user.username|e }} looks pretty normal
{% endif %}
For loops work very similarly to Django, but notably the Jinja2 special variable for the loop context is called loop, not forloop as in Django.
In addition, the Django empty argument is called else in Jinja2. For example, the Django template:
{% for item in items %}
{{ item }}
{% empty %}
No items!
{% endfor %}
...looks like this in Jinja2:
{% for item in items %}
{{ item }}
{% else %}
No items!
{% endfor %}
The {% cycle %} tag does not exist in Jinja2; however, you can achieve the same output by using the cycle method on the loop context special variable.
The following Django template:
{% for user in users %}
<li class="{% cycle 'odd' 'even' %}">{{ user }}</li>
{% endfor %}
...looks like this in Jinja2:
{% for user in users %}
<li class="{{ loop.cycle('odd', 'even') }}">{{ user }}</li>
{% endfor %}
There is no equivalent of {% cycle ... as variable %}.
If you have used Mako so far and want to switch to Jinja2 you can configure Jinja2 to look more like Mako:
env = Environment('<%', '%>', '${', '}', '<%doc>', '</%doc>', '%', '##')
With an environment configured like that, Jinja2 should be able to interpret a small subset of Mako templates. Jinja2 does not support embedded Python code, so you would have to move that out of the template. The syntax for defs (which are called macros in Jinja2) and template inheritance is different too. The following Mako template:
<%inherit file="layout.html" />
<%def name="title()">Page Title</%def>
<ul>
% for item in list:
<li>${item}</li>
% endfor
</ul>
Looks like this in Jinja2 with the above configuration:
<% extends "layout.html" %>
<% block title %>Page Title<% endblock %>
<% block body %>
<ul>
% for item in list:
<li>${item}</li>
% endfor
</ul>
<% endblock %>