1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
|
Switching from other Template Engines
=====================================
.. highlight:: html+jinja
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.
Jinja1
------
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.
API
~~~
Loaders
Jinja2 uses a different loader API. Because the internal representation
of templates changed there is no longer support for external caching
systems such as memcached. The memory consumed by templates is comparable
with regular Python modules now and external caching doesn't give any
advantage. If you have used a custom loader in the past have a look at
the new :ref:`loader API <loaders>`.
Loading templates from strings
In the past it was possible to generate templates from a string with the
default environment configuration by using `jinja.from_string`. Jinja2
provides a :class:`Template` class that can be used to do the same, but
with optional additional configuration.
Automatic unicode conversion
Jinja1 performed automatic conversion of bytestrings in a given encoding
into unicode objects. This conversion is no longer implemented as it
was inconsistent as most libraries are using the regular Python ASCII
bytestring to Unicode conversion. An application powered by Jinja2
*has to* use unicode internally everywhere or make sure that Jinja2 only
gets unicode strings passed.
i18n
Jinja1 used custom translators for internationalization. i18n is now
available as Jinja2 extension and uses a simpler, more gettext friendly
interface and has support for babel. For more details see
:ref:`i18n-extension`.
Internal methods
Jinja1 exposed a few internal methods on the environment object such
as `call_function`, `get_attribute` and others. While they were marked
as being an internal method it was possible to override them. Jinja2
doesn't have equivalent methods.
Sandbox
Jinja1 was running sandbox mode by default. Few applications actually
used that feature so it became optional in Jinja2. For more details
about the sandboxed execution see :class:`SandboxedEnvironment`.
Context
Jinja1 had a stacked context as storage for variables passed to the
environment. In Jinja2 a similar object exists but it doesn't allow
modifications nor is it a singleton. As inheritance is dynamic now
multiple context objects may exist during template evaluation.
Filters and Tests
Filters and tests are regular functions now. It's no longer necessary
and allowed to use factory functions.
Templates
~~~~~~~~~
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
:ref:`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 :ref:`accessing-the-parent-loop` for more details.
Django
------
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.
Method Calls
~~~~~~~~~~~~
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.
Conditions
~~~~~~~~~~
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 %}
Filter Arguments
~~~~~~~~~~~~~~~~
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.
Tests
~~~~~
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 %}
Loops
~~~~~
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 %}
Cycle
~~~~~
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 %}``.
Mako
----
.. highlight:: html+mako
If you have used Mako so far and want to switch to Jinja2 you can configure
Jinja2 to look more like Mako:
.. sourcecode:: python
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 %>
|