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 | |
| 6 | If you have used a different template engine in the past and want to swtich |
| 7 | to Jinja2 here is a small guide that shows the basic syntatic and semantic |
| 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 | |
| 65 | |
| 66 | Templates |
| 67 | ~~~~~~~~~ |
| 68 | |
| 69 | Jinja2 has mostly the same syntax as Jinja1. The only difference is that |
| 70 | assigning variables doesn't use `set` as keyword now. The following |
| 71 | example shows a Jinja1 variable assignment:: |
| 72 | |
| 73 | {% set foo = 42 %} |
| 74 | |
| 75 | In Jinja2 the `set` is ommited:: |
| 76 | |
| 77 | {% foo = 42 %} |
| 78 | |
| 79 | Additionally macros require parentheses around the argument list now. |
| 80 | |
| 81 | Jinja2 allows dynamic inheritance now and dynamic includes. The old helper |
| 82 | function `rendertemplate` is gone now, `include` can be used instead. |
| 83 | Additionally includes no longer import macros and variable assignments, for |
| 84 | that the new `import` tag is used. This concept is explained in the |
| 85 | :ref:`import` documentation. |
| 86 | |
| 87 | Currently there is no support for the `recursive` modifier of for loops! |
| 88 | |
| 89 | |
| 90 | Django |
| 91 | ------ |
| 92 | |
| 93 | If you have previously worked with Django templates, you should find |
| 94 | Jinja2 very familiar. In fact, most of the syntax elements look and |
| 95 | work the same. |
| 96 | |
| 97 | However, Jinja2 provides some more syntax elements covered in the |
| 98 | documentation and some work a bit different. |
| 99 | |
| 100 | This section covers the template changes. As the API is fundamentally |
| 101 | different we won't cover it here. |
| 102 | |
| 103 | Method Calls |
| 104 | ~~~~~~~~~~~~ |
| 105 | |
| 106 | In Django method calls work implicitly. With Jinja2 you have to specify that |
| 107 | you want to call an object. Thus this Django code:: |
| 108 | |
| 109 | {% for page in user.get_created_pages %} |
| 110 | ... |
| 111 | {% endfor %} |
| 112 | |
| 113 | will look like this in Jinja:: |
| 114 | |
| 115 | {% for page in user.get_created_pages() %} |
| 116 | ... |
| 117 | {% endfor %} |
| 118 | |
| 119 | This allows you to pass variables to the function which is also used for macros |
| 120 | which is not possible in Django. |
| 121 | |
| 122 | Conditions |
| 123 | ~~~~~~~~~~ |
| 124 | |
| 125 | In Django you can use the following constructs to check for equality:: |
| 126 | |
Georg Brandl | 3863b65 | 2008-05-11 12:56:50 +0200 | [diff] [blame^] | 127 | {% ifequal foo "bar" %} |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 128 | ... |
| 129 | {% else %} |
| 130 | ... |
Georg Brandl | 3863b65 | 2008-05-11 12:56:50 +0200 | [diff] [blame^] | 131 | {% endifequal %} |
Armin Ronacher | 5cdc1ac | 2008-05-07 12:17:18 +0200 | [diff] [blame] | 132 | |
| 133 | In Jinja2 you can use the normal if statement in combination with operators:: |
| 134 | |
| 135 | {% if foo == 'bar' %} |
| 136 | ... |
| 137 | {% else %} |
| 138 | ... |
| 139 | {% endif %} |
| 140 | |
| 141 | You can also have multiple elif branches in your template:: |
| 142 | |
| 143 | {% if something %} |
| 144 | ... |
| 145 | {% elif otherthing %} |
| 146 | ... |
| 147 | {% elif foothing %} |
| 148 | ... |
| 149 | {% else %} |
| 150 | ... |
| 151 | {% endif %} |
| 152 | |
| 153 | Filter Arguments |
| 154 | ~~~~~~~~~~~~~~~~ |
| 155 | |
| 156 | Jinja2 provides more than one argument for filters. Also the syntax for |
| 157 | argument passing is different. A template that looks like this in Django:: |
| 158 | |
| 159 | {{ items|join:", " }} |
| 160 | |
| 161 | looks like this in Jinja2:: |
| 162 | |
| 163 | {{ items|join(', ') }} |
| 164 | |
| 165 | In fact it's a bit more verbose but it allows different types of arguments - |
| 166 | including variables - and more than one of them. |
| 167 | |
| 168 | Tests |
| 169 | ~~~~~ |
| 170 | |
| 171 | In addition to filters there also are tests you can perform using the is |
| 172 | operator. Here are some examples:: |
| 173 | |
| 174 | {% if user.user_id is odd %} |
| 175 | {{ user.username|e }} is odd |
| 176 | {% else %} |
| 177 | hmm. {{ user.username|e }} looks pretty normal |
| 178 | {% endif %} |
| 179 | |
| 180 | |
| 181 | Mako |
| 182 | ---- |
| 183 | |
| 184 | .. highlight:: html+mako |
| 185 | |
| 186 | If you have used Mako so far and want to switch to Jinja2 you can configure |
| 187 | Jinja2 to look more like Mako: |
| 188 | |
| 189 | .. sourcecode:: python |
| 190 | |
| 191 | env = Environment('<%', '%>', '${', '}', '%') |
| 192 | |
| 193 | Once the environment is configure like that Jinja2 should be able to interpret |
| 194 | a small subset of Mako templates. Jinja2 does not support embedded Python code |
| 195 | so you would have to move that out of the template. The syntax for defs (in |
| 196 | Jinja2 defs are called macros) and template inheritance is different too. The |
| 197 | following Mako template:: |
| 198 | |
| 199 | <%inherit file="layout.html" /> |
| 200 | <%def name="title()">Page Title</%def> |
| 201 | <ul> |
| 202 | % for item in list: |
| 203 | <li>${item}</li> |
| 204 | % endfor |
| 205 | </ul> |
| 206 | |
| 207 | Looks like this in Jinja2 with the above configuration:: |
| 208 | |
| 209 | <% extends "layout.html" %> |
| 210 | <% block title %>Page Title<% endblock %> |
| 211 | <% block body %> |
| 212 | <ul> |
| 213 | % for item in list: |
| 214 | <li>${item}</li> |
| 215 | % endfor |
| 216 | </ul> |
| 217 | <% endblock %> |