Transition to Jinja templates from Django templates
If you're accustomed to using Django templates, this section describes the finer details you need to be aware of when using Jinja templates, such as: what Django template knowledge you can leverage in Jinja templates, what works differently in Jinja templates compared to Django templates and what are new things you need to learn that you'll come to appreciate in Jinja templates.
If you've never used Django templates, you can skip to the next section on Jinja template configuration in Django, as most of what follows is intended for experienced Django template users.
What works the same way in Jinja and Django templates
Just because Jinja is an entirely different template engine, doesn't mean it's radically different from Django's built-in template engine. You can expect to use the same approach for: Variables & blocks, conditionals & loops, comments, as well as spacing & special characters.
Variables and blocks
Curly braces {}
are
broadly used in Jinja templates just like they're used in Django
templates. To output a variable in Jinja you use the same
{{myvariable}}
syntax. Similarly, you also name blocks
to inherit snippets between templates with the {% block
footer %} {% endblock %}
syntax. In addition, Jinja also
uses the same Django {% extends "base.html" %}
syntax
to create parent/child relationships between templates.
Conditionals and loops
Jinja uses the same Django syntax
to create conditionals: {% if variable %}{% elif
othervariable %}{% else %}{% endif %}
. In addition, Jinja
also uses the same for loop syntax as Django: {% for item in
listofitems %}{{item}}{% endfor %}
.
Comments
Jinja also uses the same comment
tag as Django: {# This is a template comment that isn't
rendered #}
. However, note Jinja uses the {# #}
tag for both single and multi-line comments.
Spacing and special characters
Since Jinja templates were
inspired from Django templates, Jinja uses a similar approach to
dealing with spacing and special characters. For example, things
like spacing filters (e.g.center
and
wordwrap
) and special character handling
(e.g.safe
and escape
filters ) work the
same way in Jinja templates as they do in Django templates.
What works differently in Jinja templates compared to Django templates
However, not everything works the same way in Jinja templates, here are some Django template techniques you'll need to relearn to work with Jinja templates.
Filters
Although Jinja uses the same pipe
|
symbol to apply filters to variables, Jinja filters
are technically classified into filters and tests. In Django
templates there are just filters that perform tests (e.g.
divisibleby
) but in Jinja these type constructs are
called tests and use the conditional syntax {% if variable is
test %}
instead of the standard pipe |
symbol.
In addition, Jinja filters and
tests are backed by standard methods. This has the advantage that
passing arguments to Jinja filters and tests is as simple as a
method call (e.g.{{variable|filesizeformat(true)}}
)
vs. the unintuitive Django filter argument syntax of using a colon
and even requiring to parse arguments in custom Django filters
(e.g. {{variable|get_digit:"1"}}
).
It's also possible to create
custom Jinja filters and tests -- in addition to the built-in Jinja filters and tests which are similar to Django built-in filters.
However, unlike Django filters which are loaded into templates via
the {% load %}
tag, Jinja custom filters and tests are
registered globally and become accessible to all Jinja templates
like Django context processors.
Context processors
Context processors give Django templates access to sets of variables across every template in a project, but in Jinja this functionality is called global variables. This is one area where you'll likely miss the Django template functionality of simply declaring context processors and getting access to sets of variables. However, it's relatively easy to create Jinja global variables to become accessible on all Jinja templates and act as Django context processors.
No date elements like the {% now %} tag and filters like time and timesince
Jinja in its out-of-the-box state
provides no tags or filters to work with dates or times. Although
Jinja does offer the format
filter that works just
like Python's standard method and can be used for date formatting,
you'll need to write your own custom filters and tags to deal with
date and time elements in a more advanced way.
{% comment %} tag not supported
Jinja uses the {# #}
tag to define either single and multi-line comments, so there's no
support for the {% comment %}
which in Django
templates is used for multi-line comments.
{% load %} tag not supported
In Jinja the {% load
%}
tag to import custom tags and filters is not supported.
In Jinja custom tags and filters are registered globally and
automatically become accessible to all Jinja templates.
Use {{super()}} instead of {{block.super}}
In Django templates you use the
syntax {{ block.super }}
to access the contents of a
parent template's block. In Jinja you must use the
{{super()}}
syntax to gain access to the contents of a
parent template's block.
{% csrf_token %} tag not supported instead use csrf_input or csrf_token variables
In Django templates when you
create a form that has an HTTP POST action, you place the {%
csrf_token %}
tag in its body to generate a special token
that avoids XSS('Cross-site scripting'). To replicate this behavior
in Jinja you must use the csrf_input
variable (e.g.
{{csrf_input}}
generates a string like <input
type="hidden" name="csrfmiddlewaretoken"
value="4565465747487">
) or use the
csrf_token
variable which contains the raw CSRF token
(e.g.4565465747487
).
{% for %} loop variables
In Django templates the context
of {% for %}
loops offers access to a series of
variables (e.g. counter, first and last iteration). Jinja templates
offer a similar variable in the context of {% for %}
but they are not identical.
{% empty %} tag not supported in loops, use the {% else %} tag
{% for %}
loops in
Django templates support the {% empty %}
clause as a
last argument to generate logic or a message when an iteration is
empty. In Jinja {% for %}
loops you can use the
{% else %}
clause as a last argument to generate logic
or a message when an iteration is empty.
{% groupby %} tag not supported, use the groupby filter
Django templates support the
{% groupby %}
tag to rearrange dictionaries or objects
based on different attributes. In Jinja you can achieve the same
functionality but you must do it through the groupby
filter as described in the Jinja groupby
filter.
{% cycle %} tag not supported, use the cycler function or the loop.cycle variable in {% for %} loops
Django templates support the
{% cycle %}
tag to cycle over a list of values. In
Jinja this functionality is available in two forms. You can use the
cycler
method if you require the functionality outside
of loops. Or you can use the loop.cycle
function
available in all {% for %}
loops.
{% lorem %} tag not supported, use the lipsum function
Django templates support the
{% lorem %}
tag to generate random latin text as
filler content. In Jinja you can achieve the same functionality
with the lipsum
function.
Other miscellaneous tags like {% static %}, {% trans %}, {% blocktrans %}, {% url %} and {% debug %} not supported out-of-the-box
A series of Django template tags
like {% static %}
and {% trans %}
are
simply not available out-of-the-box in Jinja. However, there are third party
solutions that offer similar solutions for Jinja, wnich include using either Jinja globals or Jinja extensions.
New concepts and features in Jinja templates vs. Django templates
Now that you know what Django template knowledge you can leverage and what techniques you'll need to relearn to effectively work with Jinja templates, let's take a look at some concepts that only apply to Jinja templates.
More useful built-in filters, tests and more resemblance to a Python environment
Jinja templates offer a variety of built-in filters and tests that are sorely missing in Django templates. For example, for something as simple as checking variable types (e.g. string, number, iterable, etc), Jinja offers a series of built-in tests for this purpose, where as in Django this requires creating custom filters.
Access and manipulation of
complex data types (e.g. objects and dictionaries) is also vastly
improved in Jinja templates vs. Django templates. For example,
Jinja offers filters such as reject
,
select
and map
to prune, filter or alter
data sub-sets on a template, a technique that although frowned upon
by web purists (i.e. those who stand by only manipulating data in
views) are a very common requirement in real & time-constrained
projects.
Jinja templates also support
syntax that is more in-line with a standard Python environment. For
example, in Django something like accessing a dictionary key
through a variable requires a custom filter, where as in Jinja
templates this works with standard Python syntax (e.g. if you have
the variables stores={"key1":"value1",
"key2":"value2"}
and var="key1"
, Django
template can't do stores.get(var)
which is standard
Python syntax, but in Jinja this works out-of-the-box as expected
of a Python environment).
Global functions
Jinja also supports a series of
global functions. For example, Jinja offers the range
function that works just like Python's standard function which is
useful in loops (e.g. {% for number in range(50 -
coffeeshops|count) %}
). In addition, Jinja also offers the
global functions: lipsum
to generate dummy placeholder
content, dict
to generate dictionaries,
cycler
to generate a cycle over elements and
joiner
to join sections.
Flexible tag nesting, conditionals and references
Jinja is very flexible in terms
of nesting tags, particularly compared to what's permissible in
Django templates. For example, in Jinja you can even conditionally
apply the {% extends %}
tag (e.g. {% if user
%}{% extends "base.html" %}{% else %}{% extends "signup_base.html"
%}{% endif %}
) or also use variable reference names with
inline conditions (e.g.{% extends layout_template if
layout_template is defined else 'master.html' %}
) something
that's not possible in Django templates.
Macros
In Jinja macros allow you to define function-like snippets with complex layouts that can be called from any template with different instance values. Macros are particularly useful to limit the spread of complex layouts across templates. With macros you define a complex layout once (i.e. as a macro) and invoke it with different parameters to output the complex layout customized every single time, just as if were a function.
Flexible variable assignment in templates with less restrictive scope
In Jinja you can use the {%
set %}
tag to define variables to have a valid scope until
the end of the template. Although Jinja also supports the {%
with %}
tag -- just like the Django template version -- the
{% with %}
tag can become cumbersome for multiple
variable definitions because it requires closing the scope with
{% endwith %}
every time. The {% set %}
is a good alternative for global template variables because you
only require the initial definition and the scope propagates to end
of the template without having to worry about closing the
scope.
Line statements
Jinja supports the definition of
logical statements in what it calls line statements. By default, a
line statement is preceded with the #
symbol and can
serve as an alternative to tag syntax. For example, the {%
for %}
tag statement {% for item in items %}
can use the equivalent line statement # for item in
items
, just as the tag statement {% endfor %}
can use the equivalent line statement # endfor
. Line
statements more than anything give templates a Python feel to them
which can make complex logic easier to decipher vs. using tag
statements that require the {% %}
syntax.