Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 1 | Switching from other Template Engines |
| 2 | ===================================== |
| 3 | |
| 4 | .. highlight:: html+jinja |
| 5 | |
Sakti Dwi Cahyono | a29f9dd | 2013-02-15 14:08:45 +0700 | [diff] [blame] | 6 | If you have used a different template engine in the past and want to switch |
Alex Chan | 972c030 | 2015-04-05 22:42:34 +0100 | [diff] [blame] | 7 | to Jinja2 here is a small guide that shows the basic syntactic and semantic |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 8 | changes between some common, similar text template engines for Python. |
| 9 | |
| 10 | Jinja1 |
| 11 | ------ |
| 12 | |
| 13 | Jinja2 is mostly compatible with Jinja1 in terms of API usage and template |
| 14 | syntax. The differences between Jinja1 and 2 are explained in the following |
| 15 | list. |
| 16 | |
| 17 | API |
| 18 | ~~~ |
| 19 | |
| 20 | Loaders |
| 21 | Jinja2 uses a different loader API. Because the internal representation |
| 22 | of templates changed there is no longer support for external caching |
| 23 | systems such as memcached. The memory consumed by templates is comparable |
| 24 | with regular Python modules now and external caching doesn't give any |
| 25 | advantage. If you have used a custom loader in the past have a look at |
| 26 | the new :ref:`loader API <loaders>`. |
| 27 | |
| 28 | Loading templates from strings |
| 29 | In the past it was possible to generate templates from a string with the |
| 30 | default environment configuration by using `jinja.from_string`. Jinja2 |
| 31 | provides a :class:`Template` class that can be used to do the same, but |
| 32 | with optional additional configuration. |
| 33 | |
| 34 | Automatic unicode conversion |
| 35 | Jinja1 performed automatic conversion of bytestrings in a given encoding |
| 36 | into unicode objects. This conversion is no longer implemented as it |
| 37 | was inconsistent as most libraries are using the regular Python ASCII |
| 38 | bytestring to Unicode conversion. An application powered by Jinja2 |
| 39 | *has to* use unicode internally everywhere or make sure that Jinja2 only |
| 40 | gets unicode strings passed. |
| 41 | |
| 42 | i18n |
| 43 | Jinja1 used custom translators for internationalization. i18n is now |
| 44 | available as Jinja2 extension and uses a simpler, more gettext friendly |
| 45 | interface and has support for babel. For more details see |
| 46 | :ref:`i18n-extension`. |
| 47 | |
| 48 | Internal methods |
| 49 | Jinja1 exposed a few internal methods on the environment object such |
| 50 | as `call_function`, `get_attribute` and others. While they were marked |
| 51 | as being an internal method it was possible to override them. Jinja2 |
| 52 | doesn't have equivalent methods. |
| 53 | |
| 54 | Sandbox |
| 55 | Jinja1 was running sandbox mode by default. Few applications actually |
| 56 | used that feature so it became optional in Jinja2. For more details |
| 57 | about the sandboxed execution see :class:`SandboxedEnvironment`. |
| 58 | |
| 59 | Context |
| 60 | Jinja1 had a stacked context as storage for variables passed to the |
| 61 | environment. In Jinja2 a similar object exists but it doesn't allow |
| 62 | modifications nor is it a singleton. As inheritance is dynamic now |
| 63 | multiple context objects may exist during template evaluation. |
| 64 | |
Armin Ronacher | 09c002e | 2008-05-10 22:21:30 +0200 | [diff] [blame] | 65 | Filters and Tests |
| 66 | Filters and tests are regular functions now. It's no longer necessary |
| 67 | and allowed to use factory functions. |
| 68 | |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 69 | |
| 70 | Templates |
| 71 | ~~~~~~~~~ |
| 72 | |
Armin Ronacher | 2b22874 | 2008-05-18 20:29:32 +0200 | [diff] [blame] | 73 | Jinja2 has mostly the same syntax as Jinja1. What's different is that |
| 74 | macros require parentheses around the argument list now. |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 75 | |
Armin Ronacher | 2b22874 | 2008-05-18 20:29:32 +0200 | [diff] [blame] | 76 | Additionally Jinja2 allows dynamic inheritance now and dynamic includes. |
| 77 | The old helper function `rendertemplate` is gone now, `include` can be used |
| 78 | instead. Includes no longer import macros and variable assignments, for |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 79 | that the new `import` tag is used. This concept is explained in the |
| 80 | :ref:`import` documentation. |
| 81 | |
Armin Ronacher | e224488 | 2008-05-19 09:25:57 +0200 | [diff] [blame] | 82 | Another small change happened in the `for`-tag. The special loop variable |
| 83 | doesn't have a `parent` attribute, instead you have to alias the loop |
| 84 | yourself. See :ref:`accessing-the-parent-loop` for more details. |
| 85 | |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 86 | |
| 87 | Django |
| 88 | ------ |
| 89 | |
| 90 | If you have previously worked with Django templates, you should find |
| 91 | Jinja2 very familiar. In fact, most of the syntax elements look and |
| 92 | work the same. |
| 93 | |
| 94 | However, Jinja2 provides some more syntax elements covered in the |
| 95 | documentation and some work a bit different. |
| 96 | |
| 97 | This section covers the template changes. As the API is fundamentally |
| 98 | different we won't cover it here. |
| 99 | |
| 100 | Method Calls |
| 101 | ~~~~~~~~~~~~ |
| 102 | |
Markus Unterwaditzer | f1668bd | 2015-03-11 21:26:24 +0100 | [diff] [blame] | 103 | In Django method calls work implicitly, while Jinja requires the explicit |
| 104 | Python syntax. Thus this Django code:: |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 105 | |
| 106 | {% for page in user.get_created_pages %} |
| 107 | ... |
| 108 | {% endfor %} |
Adam Chainz | 382ee70 | 2014-07-12 23:03:55 +0100 | [diff] [blame] | 109 | |
| 110 | ...looks like this in Jinja:: |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 111 | |
| 112 | {% for page in user.get_created_pages() %} |
| 113 | ... |
| 114 | {% endfor %} |
| 115 | |
Adam Chainz | 382ee70 | 2014-07-12 23:03:55 +0100 | [diff] [blame] | 116 | This allows you to pass variables to the method, which is not possible in |
| 117 | Django. This syntax is also used for macros. |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 118 | |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 119 | Filter Arguments |
| 120 | ~~~~~~~~~~~~~~~~ |
| 121 | |
| 122 | Jinja2 provides more than one argument for filters. Also the syntax for |
| 123 | argument passing is different. A template that looks like this in Django:: |
| 124 | |
| 125 | {{ items|join:", " }} |
| 126 | |
| 127 | looks like this in Jinja2:: |
| 128 | |
| 129 | {{ items|join(', ') }} |
| 130 | |
Adam Chainz | 382ee70 | 2014-07-12 23:03:55 +0100 | [diff] [blame] | 131 | It is a bit more verbose, but it allows different types of arguments - |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 132 | including variables - and more than one of them. |
| 133 | |
| 134 | Tests |
| 135 | ~~~~~ |
| 136 | |
| 137 | In addition to filters there also are tests you can perform using the is |
| 138 | operator. Here are some examples:: |
| 139 | |
| 140 | {% if user.user_id is odd %} |
| 141 | {{ user.username|e }} is odd |
| 142 | {% else %} |
| 143 | hmm. {{ user.username|e }} looks pretty normal |
| 144 | {% endif %} |
| 145 | |
Armin Ronacher | 9bb7e47 | 2008-05-28 11:26:59 +0200 | [diff] [blame] | 146 | Loops |
| 147 | ~~~~~ |
| 148 | |
Adam Chainz | 382ee70 | 2014-07-12 23:03:55 +0100 | [diff] [blame] | 149 | For loops work very similarly to Django, but notably the Jinja2 special |
| 150 | variable for the loop context is called `loop`, not `forloop` as in Django. |
Ned Jackson Lovely | 7336b7a | 2012-03-12 20:45:08 -0400 | [diff] [blame] | 151 | |
Adam Chainz | 382ee70 | 2014-07-12 23:03:55 +0100 | [diff] [blame] | 152 | In addition, the Django `empty` argument is called `else` in Jinja2. For |
| 153 | example, the Django template:: |
Ned Jackson Lovely | 7336b7a | 2012-03-12 20:45:08 -0400 | [diff] [blame] | 154 | |
| 155 | {% for item in items %} |
Armin Ronacher | 4b2c926 | 2013-05-19 11:36:52 +0100 | [diff] [blame] | 156 | {{ item }} |
Ned Jackson Lovely | 7336b7a | 2012-03-12 20:45:08 -0400 | [diff] [blame] | 157 | {% empty %} |
| 158 | No items! |
| 159 | {% endfor %} |
| 160 | |
Adam Chainz | 382ee70 | 2014-07-12 23:03:55 +0100 | [diff] [blame] | 161 | ...looks like this in Jinja2:: |
Ned Jackson Lovely | 7336b7a | 2012-03-12 20:45:08 -0400 | [diff] [blame] | 162 | |
| 163 | {% for item in items %} |
Armin Ronacher | 4b2c926 | 2013-05-19 11:36:52 +0100 | [diff] [blame] | 164 | {{ item }} |
Ned Jackson Lovely | 7336b7a | 2012-03-12 20:45:08 -0400 | [diff] [blame] | 165 | {% else %} |
| 166 | No items! |
| 167 | {% endfor %} |
Armin Ronacher | 9bb7e47 | 2008-05-28 11:26:59 +0200 | [diff] [blame] | 168 | |
Armin Ronacher | f288b7a | 2008-06-19 09:41:56 +0200 | [diff] [blame] | 169 | Cycle |
| 170 | ~~~~~ |
| 171 | |
Adam Chainz | 382ee70 | 2014-07-12 23:03:55 +0100 | [diff] [blame] | 172 | The ``{% cycle %}`` tag does not exist in Jinja2; however, you can achieve the |
| 173 | same output by using the `cycle` method on the loop context special variable. |
Armin Ronacher | f288b7a | 2008-06-19 09:41:56 +0200 | [diff] [blame] | 174 | |
| 175 | The following Django template:: |
| 176 | |
| 177 | {% for user in users %} |
| 178 | <li class="{% cycle 'odd' 'even' %}">{{ user }}</li> |
| 179 | {% endfor %} |
| 180 | |
Adam Chainz | 382ee70 | 2014-07-12 23:03:55 +0100 | [diff] [blame] | 181 | ...looks like this in Jinja2:: |
Armin Ronacher | f288b7a | 2008-06-19 09:41:56 +0200 | [diff] [blame] | 182 | |
| 183 | {% for user in users %} |
| 184 | <li class="{{ loop.cycle('odd', 'even') }}">{{ user }}</li> |
| 185 | {% endfor %} |
| 186 | |
| 187 | There is no equivalent of ``{% cycle ... as variable %}``. |
| 188 | |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 189 | |
| 190 | Mako |
| 191 | ---- |
| 192 | |
| 193 | .. highlight:: html+mako |
| 194 | |
| 195 | If you have used Mako so far and want to switch to Jinja2 you can configure |
| 196 | Jinja2 to look more like Mako: |
| 197 | |
| 198 | .. sourcecode:: python |
| 199 | |
Florent Xicluna | e04e32f | 2012-02-05 12:14:08 +0100 | [diff] [blame] | 200 | env = Environment('<%', '%>', '${', '}', '<%doc>', '</%doc>', '%', '##') |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 201 | |
Adam Chainz | 382ee70 | 2014-07-12 23:03:55 +0100 | [diff] [blame] | 202 | With an environment configured like that, Jinja2 should be able to interpret |
| 203 | a small subset of Mako templates. Jinja2 does not support embedded Python |
| 204 | code, so you would have to move that out of the template. The syntax for defs |
| 205 | (which are called macros in Jinja2) and template inheritance is different too. |
| 206 | The following Mako template:: |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 207 | |
| 208 | <%inherit file="layout.html" /> |
| 209 | <%def name="title()">Page Title</%def> |
| 210 | <ul> |
| 211 | % for item in list: |
| 212 | <li>${item}</li> |
| 213 | % endfor |
| 214 | </ul> |
| 215 | |
| 216 | Looks like this in Jinja2 with the above configuration:: |
| 217 | |
| 218 | <% extends "layout.html" %> |
| 219 | <% block title %>Page Title<% endblock %> |
| 220 | <% block body %> |
| 221 | <ul> |
| 222 | % for item in list: |
| 223 | <li>${item}</li> |
| 224 | % endfor |
| 225 | </ul> |
| 226 | <% endblock %> |