summaryrefslogtreecommitdiff
path: root/docs/switching.rst
blob: 8225b2ee05fc45ed794271d31a39ec3b03bdddd4 (plain)
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
Switching from other Template Engines
=====================================

.. highlight:: html+jinja

If you have used a different template engine in the past and want to switch
to Jinja here is a small guide that shows the basic syntactic and semantic
changes between some common, similar text template engines for Python.

Jinja 1
-------

Jinja 2 is mostly compatible with Jinja 1 in terms of API usage and template
syntax.  The differences between Jinja 1 and 2 are explained in the following
list.

API
~~~

Loaders
    Jinja 2 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`.  Jinja 2
    provides a :class:`Template` class that can be used to do the same, but
    with optional additional configuration.

Automatic unicode conversion
    Jinja 1 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 Jinja 2
    *has to* use unicode internally everywhere or make sure that Jinja 2 only
    gets unicode strings passed.

i18n
    Jinja 1 used custom translators for internationalization.  i18n is now
    available as Jinja 2 extension and uses a simpler, more gettext friendly
    interface and has support for babel.  For more details see
    :ref:`i18n-extension`.

Internal methods
    Jinja 1 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.  Jinja 2
    doesn't have equivalent methods.

Sandbox
    Jinja 1 was running sandbox mode by default.  Few applications actually
    used that feature so it became optional in Jinja 2.  For more details
    about the sandboxed execution see :class:`SandboxedEnvironment`.

Context
    Jinja 1 had a stacked context as storage for variables passed to the
    environment.  In Jinja 2 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
~~~~~~~~~

Jinja 2 has mostly the same syntax as Jinja 1.  What's different is that
macros require parentheses around the argument list now.

Additionally Jinja 2 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
Jinja very familiar.  In fact, most of the syntax elements look and
work the same.

However, Jinja 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.

Filter Arguments
~~~~~~~~~~~~~~~~

Jinja 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 Jinja::

    {{ 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 Jinja special
variable for the loop context is called `loop`, not `forloop` as in Django.

In addition, the Django `empty` argument is called `else` in Jinja. For
example, the Django template::

    {% for item in items %}
        {{ item }}
    {% empty %}
        No items!
    {% endfor %}

...looks like this in Jinja::

    {% for item in items %}
        {{ item }}
    {% else %}
        No items!
    {% endfor %}

Cycle
~~~~~

The ``{% cycle %}`` tag does not exist in Jinja; 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 Jinja::

    {% 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 Jinja you can configure
Jinja to look more like Mako:

.. sourcecode:: python

    env = Environment('<%', '%>', '${', '}', '<%doc>', '</%doc>', '%', '##')

With an environment configured like that, Jinja should be able to interpret
a small subset of Mako templates.  Jinja 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 Jinja) 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 Jinja 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 %>