commit | author | age
|
e45645
|
1 |
.. _templates_chapter: |
CM |
2 |
|
9cafa3
|
3 |
Templates |
CM |
4 |
========= |
|
5 |
|
ac568b
|
6 |
A :term:`template` is a file on disk which can be used to render dynamic data |
SP |
7 |
provided by a :term:`view`. :app:`Pyramid` offers a number of ways to perform |
|
8 |
templating tasks out of the box, and provides add-on templating support through |
|
9 |
a set of bindings packages. |
9ec2d6
|
10 |
|
ac568b
|
11 |
Before discussing how built-in templates are used in detail, we'll discuss two |
SP |
12 |
ways to render templates within :app:`Pyramid` in general: directly and via |
|
13 |
renderer configuration. |
9cafa3
|
14 |
|
8c56ae
|
15 |
.. index:: |
9ec2d6
|
16 |
single: templates used directly |
8c56ae
|
17 |
|
9ec2d6
|
18 |
.. _templates_used_directly: |
a9fed7
|
19 |
|
470ad6
|
20 |
Using Templates Directly |
CD |
21 |
------------------------ |
9cafa3
|
22 |
|
ac568b
|
23 |
The most straightforward way to use a template within :app:`Pyramid` is to |
SP |
24 |
cause it to be rendered directly within a :term:`view callable`. You may use |
|
25 |
whatever API is supplied by a given templating engine to do so. |
9cafa3
|
26 |
|
ac568b
|
27 |
:app:`Pyramid` provides various APIs that allow you to render templates directly |
SP |
28 |
from within a view callable. For example, if there is a :term:`Chameleon` ZPT |
|
29 |
template named ``foo.pt`` in a directory named ``templates`` in your |
|
30 |
application, you can render the template from within the body of a view |
|
31 |
callable like so: |
9cafa3
|
32 |
|
0bd110
|
33 |
.. code-block:: python |
CM |
34 |
:linenos: |
6b9fd1
|
35 |
|
fec0f0
|
36 |
from pyramid.renderers import render_to_response |
9ec2d6
|
37 |
|
6103bf
|
38 |
def sample_view(request): |
368746
|
39 |
return render_to_response('templates/foo.pt', |
SP |
40 |
{'foo':1, 'bar':2}, |
250c02
|
41 |
request=request) |
CM |
42 |
|
c05651
|
43 |
The ``sample_view`` :term:`view callable` function above returns a |
ac568b
|
44 |
:term:`response` object which contains the body of the ``templates/foo.pt`` |
SP |
45 |
template. In this case, the ``templates`` directory should live in the same |
|
46 |
directory as the module containing the ``sample_view`` function. The template |
|
47 |
author will have the names ``foo`` and ``bar`` available as top-level names for |
|
48 |
replacement or comparison purposes. |
f6a2c7
|
49 |
|
250c02
|
50 |
In the example above, the path ``templates/foo.pt`` is relative to the |
ac568b
|
51 |
directory containing the file which defines the view configuration. In this |
SP |
52 |
case, this is the directory containing the file that defines the |
|
53 |
``sample_view`` function. Although a renderer path is usually just a simple |
|
54 |
relative pathname, a path named as a renderer can be absolute, starting with a |
|
55 |
slash on UNIX or a drive letter prefix on Windows. The path can alternatively |
|
56 |
be an :term:`asset specification` in the form |
|
57 |
``some.dotted.package_name:relative/path``. This makes it possible to address |
|
58 |
template assets which live in another package. For example: |
9ec2d6
|
59 |
|
CM |
60 |
.. code-block:: python |
|
61 |
:linenos: |
|
62 |
|
fec0f0
|
63 |
from pyramid.renderers import render_to_response |
250c02
|
64 |
|
CM |
65 |
def sample_view(request): |
3de42f
|
66 |
return render_to_response('mypackage:templates/foo.pt', |
CM |
67 |
{'foo':1, 'bar':2}, |
250c02
|
68 |
request=request) |
CM |
69 |
|
ac568b
|
70 |
An asset specification points at a file within a Python *package*. In this |
SP |
71 |
case, it points at a file named ``foo.pt`` within the ``templates`` directory |
|
72 |
of the ``mypackage`` package. Using an asset specification instead of a |
|
73 |
relative template name is usually a good idea, because calls to |
|
74 |
:func:`~pyramid.renderers.render_to_response` using asset specifications will |
|
75 |
continue to work properly if you move the code containing them to another |
|
76 |
location. |
250c02
|
77 |
|
CM |
78 |
In the examples above we pass in a keyword argument named ``request`` |
ac568b
|
79 |
representing the current :app:`Pyramid` request. Passing a request keyword |
SP |
80 |
argument will cause the ``render_to_response`` function to supply the renderer |
|
81 |
with more correct system values (see :ref:`renderer_system_values`), because |
|
82 |
most of the information required to compose proper system values is present in |
|
83 |
the request. If your template relies on the name ``request`` or ``context``, |
|
84 |
or if you've configured special :term:`renderer globals`, make sure to pass |
043ccd
|
85 |
``request`` as a keyword argument in every call to a |
818768
|
86 |
``pyramid.renderers.render_*`` function. |
250c02
|
87 |
|
ac568b
|
88 |
Every view must return a :term:`response` object, except for views which use a |
SP |
89 |
:term:`renderer` named via view configuration (which we'll see shortly). The |
|
90 |
:func:`pyramid.renderers.render_to_response` function is a shortcut function |
|
91 |
that actually returns a response object. This allows the example view above to |
|
92 |
simply return the result of its call to ``render_to_response()`` directly. |
250c02
|
93 |
|
c53d82
|
94 |
Obviously not all APIs you might call to get response data will return a |
ac568b
|
95 |
response object. For example, you might render one or more templates to a |
SP |
96 |
string that you want to use as response data. The |
|
97 |
:func:`pyramid.renderers.render` API renders a template to a string. We can |
|
98 |
manufacture a :term:`response` object directly, and use that string as the body |
|
99 |
of the response: |
250c02
|
100 |
|
CM |
101 |
.. code-block:: python |
|
102 |
:linenos: |
|
103 |
|
fec0f0
|
104 |
from pyramid.renderers import render |
94b889
|
105 |
from pyramid.response import Response |
9ec2d6
|
106 |
|
CM |
107 |
def sample_view(request): |
368746
|
108 |
result = render('mypackage:templates/foo.pt', |
SP |
109 |
{'foo':1, 'bar':2}, |
250c02
|
110 |
request=request) |
9ec2d6
|
111 |
response = Response(result) |
CM |
112 |
return response |
|
113 |
|
|
114 |
Because :term:`view callable` functions are typically the only code in |
fd5ae9
|
115 |
:app:`Pyramid` that need to know anything about templates, and because view |
ac568b
|
116 |
functions are very simple Python, you can use whatever templating system with |
SP |
117 |
which you're most comfortable within :app:`Pyramid`. Install the templating |
|
118 |
system, import its API functions into your views module, use those APIs to |
|
119 |
generate a string, then return that string as the body of a :app:`Pyramid` |
9ec2d6
|
120 |
:term:`Response` object. |
CM |
121 |
|
f1aaf1
|
122 |
For example, here's an example of using "raw" Mako_ from within a |
MM |
123 |
:app:`Pyramid` :term:`view`: |
9ec2d6
|
124 |
|
CM |
125 |
.. code-block:: python |
|
126 |
:linenos: |
|
127 |
|
|
128 |
from mako.template import Template |
94b889
|
129 |
from pyramid.response import Response |
9ec2d6
|
130 |
|
CM |
131 |
def make_view(request): |
|
132 |
template = Template(filename='/templates/template.mak') |
|
133 |
result = template.render(name=request.params['name']) |
|
134 |
response = Response(result) |
|
135 |
return response |
250c02
|
136 |
|
7698bd
|
137 |
You probably wouldn't use this particular snippet in a project, because it's |
ac568b
|
138 |
easier to use the supported :ref:`Mako bindings |
SP |
139 |
<available_template_system_bindings>`. But if your favorite templating system |
|
140 |
is not supported as a renderer extension for :app:`Pyramid`, you can create |
|
141 |
your own simple combination as shown above. |
9ec2d6
|
142 |
|
CM |
143 |
.. note:: |
|
144 |
|
fec0f0
|
145 |
If you use third-party templating languages without cooperating |
fd5ae9
|
146 |
:app:`Pyramid` bindings directly within view callables, the |
ac568b
|
147 |
auto-template-reload strategy explained in :ref:`reload_templates_section` |
SP |
148 |
will not be available, nor will the template asset overriding capability |
|
149 |
explained in :ref:`overriding_assets_section` be available, nor will it be |
|
150 |
possible to use any template using that language as a :term:`renderer`. |
|
151 |
However, it's reasonably easy to write custom templating system binding |
|
152 |
packages for use under :app:`Pyramid` so that templates written in the |
|
153 |
language can be used as renderers. See |
|
154 |
:ref:`adding_and_overriding_renderers` for instructions on how to create |
|
155 |
your own template renderer and :ref:`available_template_system_bindings` |
|
156 |
for example packages. |
9ec2d6
|
157 |
|
ac568b
|
158 |
If you need more control over the status code and content-type, or other |
SP |
159 |
response attributes from views that use direct templating, you may set |
|
160 |
attributes on the response that influence these values. |
9ec2d6
|
161 |
|
ac568b
|
162 |
Here's an example of changing the content-type and status of the response |
SP |
163 |
object returned by :func:`~pyramid.renderers.render_to_response`: |
9ec2d6
|
164 |
|
CM |
165 |
.. code-block:: python |
|
166 |
:linenos: |
|
167 |
|
9d33a1
|
168 |
from pyramid.renderers import render_to_response |
9ec2d6
|
169 |
|
CM |
170 |
def sample_view(request): |
3de42f
|
171 |
response = render_to_response('templates/foo.pt', |
CM |
172 |
{'foo':1, 'bar':2}, |
250c02
|
173 |
request=request) |
9ec2d6
|
174 |
response.content_type = 'text/plain' |
CM |
175 |
response.status_int = 204 |
|
176 |
return response |
|
177 |
|
ac568b
|
178 |
Here's an example of manufacturing a response object using the result of |
SP |
179 |
:func:`~pyramid.renderers.render` (a string): |
07a69e
|
180 |
|
0bd110
|
181 |
.. code-block:: python |
CM |
182 |
:linenos: |
07a69e
|
183 |
|
fec0f0
|
184 |
from pyramid.renderers import render |
94b889
|
185 |
from pyramid.response import Response |
0b4277
|
186 |
|
6103bf
|
187 |
def sample_view(request): |
3de42f
|
188 |
result = render('mypackage:templates/foo.pt', |
368746
|
189 |
{'foo':1, 'bar':2}, |
250c02
|
190 |
request=request) |
0bd110
|
191 |
response = Response(result) |
CM |
192 |
response.content_type = 'text/plain' |
|
193 |
return response |
6b9fd1
|
194 |
|
8c56ae
|
195 |
.. index:: |
CM |
196 |
single: templates used as renderers |
c5f24b
|
197 |
single: template renderers |
CM |
198 |
single: renderer (template) |
8c56ae
|
199 |
|
250c02
|
200 |
|
6ce1e0
|
201 |
.. index:: |
CM |
202 |
pair: renderer; system values |
|
203 |
|
250c02
|
204 |
.. _renderer_system_values: |
CM |
205 |
|
|
206 |
System Values Used During Rendering |
|
207 |
----------------------------------- |
|
208 |
|
ac568b
|
209 |
When a template is rendered using :func:`~pyramid.renderers.render_to_response` |
SP |
210 |
or :func:`~pyramid.renderers.render`, or a ``renderer=`` argument to view |
eb3394
|
211 |
configuration (see :ref:`templates_used_as_renderers`), the renderer |
CM |
212 |
representing the template will be provided with a number of *system* values. |
|
213 |
These values are provided to the template: |
250c02
|
214 |
|
CM |
215 |
``request`` |
eb3394
|
216 |
The value provided as the ``request`` keyword argument to |
CM |
217 |
``render_to_response`` or ``render`` *or* the request object passed to the |
|
218 |
view when the ``renderer=`` argument to view configuration is being used to |
|
219 |
render the template. |
|
220 |
|
|
221 |
``req`` |
|
222 |
An alias for ``request``. |
|
223 |
|
|
224 |
``context`` |
|
225 |
The current :app:`Pyramid` :term:`context` if ``request`` was provided as a |
ac568b
|
226 |
keyword argument to ``render_to_response`` or ``render``, or ``None`` if the |
SP |
227 |
``request`` keyword argument was not provided. This value will always be |
|
228 |
provided if the template is rendered as the result of a ``renderer=`` |
|
229 |
argument to the view configuration being used. |
250c02
|
230 |
|
682a9b
|
231 |
``get_csrf_token()`` |
MM |
232 |
A convenience function to access the current CSRF token. See |
|
233 |
:ref:`get_csrf_token_in_templates` for more information. |
|
234 |
|
250c02
|
235 |
``renderer_name`` |
ac568b
|
236 |
The renderer name used to perform the rendering, e.g., |
SP |
237 |
``mypackage:templates/foo.pt``. |
250c02
|
238 |
|
368746
|
239 |
``renderer_info`` |
e27808
|
240 |
An object implementing the :class:`pyramid.interfaces.IRendererInfo` |
eb3394
|
241 |
interface. Basically, an object with the following attributes: ``name``, |
ac568b
|
242 |
``package``, and ``type``. |
0b4277
|
243 |
|
eb3394
|
244 |
``view`` |
ac568b
|
245 |
The view callable object that was used to render this template. If the view |
SP |
246 |
callable is a method of a class-based view, this will be an instance of the |
|
247 |
class that the method was defined on. If the view callable is a function or |
|
248 |
instance, it will be that function or instance. Note that this value will |
|
249 |
only be automatically present when a template is rendered as a result of a |
|
250 |
``renderer=`` argument; it will be ``None`` when the ``render_to_response`` |
|
251 |
or ``render`` APIs are used. |
eb3394
|
252 |
|
ac568b
|
253 |
You can define more values which will be passed to every template executed as a |
SP |
254 |
result of rendering by defining :term:`renderer globals`. |
c4599b
|
255 |
|
d168a0
|
256 |
What any particular renderer does with these system values is up to the |
f1aaf1
|
257 |
renderer itself, but most template renderers make these names available as |
MM |
258 |
top-level template variables. |
6ce1e0
|
259 |
|
CM |
260 |
.. index:: |
|
261 |
pair: renderer; templates |
250c02
|
262 |
|
9ec2d6
|
263 |
.. _templates_used_as_renderers: |
CM |
264 |
|
250c02
|
265 |
Templates Used as Renderers via Configuration |
CM |
266 |
--------------------------------------------- |
2af29e
|
267 |
|
ac568b
|
268 |
An alternative to using :func:`~pyramid.renderers.render_to_response` to render |
SP |
269 |
templates manually in your view callable code is to specify the template as a |
|
270 |
:term:`renderer` in your *view configuration*. This can be done with any of the |
373b79
|
271 |
templating languages supported by :app:`Pyramid`. |
2af29e
|
272 |
|
ac568b
|
273 |
To use a renderer via view configuration, specify a template :term:`asset |
SP |
274 |
specification` as the ``renderer`` argument, or attribute to the :term:`view |
|
275 |
configuration` of a :term:`view callable`. Then return a *dictionary* from |
|
276 |
that view callable. The dictionary items returned by the view callable will be |
|
277 |
made available to the renderer template as top-level names. |
2af29e
|
278 |
|
ac568b
|
279 |
The association of a template as a renderer for a :term:`view configuration` |
SP |
280 |
makes it possible to replace code within a :term:`view callable` that handles |
|
281 |
the rendering of a template. |
2af29e
|
282 |
|
ac568b
|
283 |
Here's an example of using a :class:`~pyramid.view.view_config` decorator to |
SP |
284 |
specify a :term:`view configuration` that names a template renderer: |
2af29e
|
285 |
|
CM |
286 |
.. code-block:: python |
|
287 |
:linenos: |
|
288 |
|
197f0c
|
289 |
from pyramid.view import view_config |
2af29e
|
290 |
|
197f0c
|
291 |
@view_config(renderer='templates/foo.pt') |
2af29e
|
292 |
def my_view(request): |
CM |
293 |
return {'foo':1, 'bar':2} |
|
294 |
|
7a60e4
|
295 |
.. note:: |
MM |
296 |
|
ac568b
|
297 |
You do not need to supply the ``request`` value as a key in the dictionary |
SP |
298 |
result returned from a renderer-configured view callable. :app:`Pyramid` |
|
299 |
automatically supplies this value for you, so that the "most correct" system |
|
300 |
values are provided to the renderer. |
250c02
|
301 |
|
0b4277
|
302 |
.. warning:: |
CM |
303 |
|
|
304 |
The ``renderer`` argument to the ``@view_config`` configuration decorator |
|
305 |
shown above is the template *path*. In the example above, the path |
|
306 |
``templates/foo.pt`` is *relative*. Relative to what, you ask? Because |
|
307 |
we're using a Chameleon renderer, it means "relative to the directory in |
ac568b
|
308 |
which the file that defines the view configuration lives". In this case, |
0b4277
|
309 |
this is the directory containing the file that defines the ``my_view`` |
7a479d
|
310 |
function. |
0b4277
|
311 |
|
55ce9d
|
312 |
Similar renderer configuration can be done imperatively. See |
2033ee
|
313 |
:ref:`views_which_use_a_renderer`. |
SP |
314 |
|
|
315 |
.. seealso:: |
|
316 |
|
|
317 |
See also :ref:`built_in_renderers`. |
250c02
|
318 |
|
0b4277
|
319 |
Although a renderer path is usually just a simple relative pathname, a path |
CM |
320 |
named as a renderer can be absolute, starting with a slash on UNIX or a drive |
ac568b
|
321 |
letter prefix on Windows. The path can alternatively be an :term:`asset |
0b4277
|
322 |
specification` in the form ``some.dotted.package_name:relative/path``, making |
a5ffd6
|
323 |
it possible to address template assets which live in another package. |
9ec2d6
|
324 |
|
0b4277
|
325 |
Not just any template from any arbitrary templating system may be used as a |
fd5ae9
|
326 |
renderer. Bindings must exist specifically for :app:`Pyramid` to use a |
f1aaf1
|
327 |
templating language template as a renderer. |
9ec2d6
|
328 |
|
ac568b
|
329 |
.. sidebar:: Why Use a Renderer via View Configuration |
9ec2d6
|
330 |
|
ac568b
|
331 |
Using a renderer in view configuration is usually a better way to render |
SP |
332 |
templates than using any rendering API directly from within a :term:`view |
|
333 |
callable` because it makes the view callable more unit-testable. Views |
|
334 |
which use templating or rendering APIs directly must return a |
|
335 |
:term:`Response` object. Making testing assertions about response objects |
|
336 |
is typically an indirect process, because it means that your test code often |
|
337 |
needs to somehow parse information out of the response body (often HTML). |
|
338 |
View callables configured with renderers externally via view configuration |
|
339 |
typically return a dictionary, as above. Making assertions about results |
|
340 |
returned in a dictionary is almost always more direct and straightforward |
|
341 |
than needing to parse HTML. |
9ec2d6
|
342 |
|
a7b1a9
|
343 |
By default, views rendered via a template renderer return a :term:`Response` |
CM |
344 |
object which has a *status code* of ``200 OK``, and a *content-type* of |
|
345 |
``text/html``. To vary attributes of the response of a view that uses a |
ac568b
|
346 |
renderer, such as the content-type, headers, or status attributes, you must use |
SP |
347 |
the API of the :class:`pyramid.response.Response` object exposed as |
a7b1a9
|
348 |
``request.response`` within the view before returning the dictionary. See |
CM |
349 |
:ref:`request_response_attr` for more information. |
250c02
|
350 |
|
ac568b
|
351 |
The same set of system values are provided to templates rendered via a renderer |
SP |
352 |
view configuration as those provided to templates rendered imperatively. See |
|
353 |
:ref:`renderer_system_values`. |
250c02
|
354 |
|
6ce1e0
|
355 |
.. index:: |
CM |
356 |
pair: debugging; templates |
|
357 |
|
49d634
|
358 |
.. _debugging_templates: |
PE |
359 |
|
488ea0
|
360 |
Debugging Templates |
CM |
361 |
------------------- |
7c525f
|
362 |
|
488ea0
|
363 |
A :exc:`NameError` exception resulting from rendering a template with an |
16f201
|
364 |
undefined variable (e.g. ``${wrong}``) might end up looking like this: |
23bfce
|
365 |
|
BL |
366 |
.. code-block:: text |
7c525f
|
367 |
|
CM |
368 |
RuntimeError: Caught exception rendering template. |
|
369 |
- Expression: ``wrong`` |
fec0f0
|
370 |
- Filename: /home/fred/env/proj/proj/templates/mytemplate.pt |
CM |
371 |
- Arguments: renderer_name: proj:templates/mytemplate.pt |
7c525f
|
372 |
template: <PageTemplateFile - at 0x1d2ecf0> |
CM |
373 |
xincludes: <XIncludes - at 0x1d3a130> |
|
374 |
request: <Request - at 0x1d2ecd0> |
fec0f0
|
375 |
project: proj |
7c525f
|
376 |
macros: <Macros - at 0x1d3aed0> |
fb6a5c
|
377 |
context: <MyResource None at 0x1d39130> |
7c525f
|
378 |
view: <function my_view at 0x1d23570> |
CM |
379 |
|
|
380 |
NameError: wrong |
|
381 |
|
488ea0
|
382 |
The output tells you which template the error occurred in, as well as |
7c525f
|
383 |
displaying the arguments passed to the template itself. |
cc8962
|
384 |
|
0b4277
|
385 |
.. index:: |
CM |
386 |
single: automatic reloading of templates |
|
387 |
single: template automatic reload |
|
388 |
|
|
389 |
.. _reload_templates_section: |
|
390 |
|
|
391 |
Automatically Reloading Templates |
|
392 |
--------------------------------- |
|
393 |
|
ac568b
|
394 |
It's often convenient to see changes you make to a template file appear |
SP |
395 |
immediately without needing to restart the application process. :app:`Pyramid` |
|
396 |
allows you to configure your application development environment so that a |
|
397 |
change to a template will be automatically detected, and the template will be |
|
398 |
reloaded on the next rendering. |
0b4277
|
399 |
|
7a60e4
|
400 |
.. warning:: |
MM |
401 |
|
ac568b
|
402 |
Auto-template-reload behavior is not recommended for production sites as it |
SP |
403 |
slows rendering slightly; it's usually only desirable during development. |
0b4277
|
404 |
|
CM |
405 |
In order to turn on automatic reloading of templates, you can use an |
ac568b
|
406 |
environment variable or a configuration file setting. |
0b4277
|
407 |
|
ac568b
|
408 |
To use an environment variable, start your application under a shell using the |
SP |
409 |
``PYRAMID_RELOAD_TEMPLATES`` operating system environment variable set to |
|
410 |
``1``, For example: |
23bfce
|
411 |
|
BL |
412 |
.. code-block:: text |
0b4277
|
413 |
|
7a60e4
|
414 |
$ PYRAMID_RELOAD_TEMPLATES=1 $VENV/bin/pserve myproject.ini |
0b4277
|
415 |
|
ac568b
|
416 |
To use a setting in the application ``.ini`` file for the same purpose, set the |
SP |
417 |
``pyramid.reload_templates`` key to ``true`` within the application's |
|
418 |
configuration section, e.g.: |
23bfce
|
419 |
|
16cd50
|
420 |
.. code-block:: ini |
7a60e4
|
421 |
:linenos: |
0b4277
|
422 |
|
7a60e4
|
423 |
[app:main] |
MM |
424 |
use = egg:MyProject |
|
425 |
pyramid.reload_templates = true |
0b4277
|
426 |
|
CM |
427 |
.. index:: |
8c56ae
|
428 |
single: template system bindings |
b9ce00
|
429 |
single: Chameleon |
8c56ae
|
430 |
single: Jinja2 |
b9ce00
|
431 |
single: Mako |
8c56ae
|
432 |
|
853f43
|
433 |
.. _available_template_system_bindings: |
ba9b0e
|
434 |
|
CM |
435 |
Available Add-On Template System Bindings |
|
436 |
----------------------------------------- |
|
437 |
|
b9ce00
|
438 |
The Pylons Project maintains several packages providing bindings to different |
MM |
439 |
templating languages including the following: |
853f43
|
440 |
|
739fbc
|
441 |
+---------------------------+----------------------------+--------------------+ |
KOP |
442 |
| Template Language | Pyramid Bindings | Default Extensions | |
|
443 |
+===========================+============================+====================+ |
|
444 |
| Chameleon_ | pyramid_chameleon_ | .pt, .txt | |
|
445 |
+---------------------------+----------------------------+--------------------+ |
|
446 |
| Jinja2_ | pyramid_jinja2_ | .jinja2 | |
|
447 |
+---------------------------+----------------------------+--------------------+ |
|
448 |
| Mako_ | pyramid_mako_ | .mak, .mako | |
|
449 |
+---------------------------+----------------------------+--------------------+ |
b9ce00
|
450 |
|
MM |
451 |
.. _Chameleon: http://chameleon.readthedocs.org/en/latest/ |
e85845
|
452 |
.. _pyramid_chameleon: |
19d341
|
453 |
https://docs.pylonsproject.org/projects/pyramid-chameleon/en/latest/ |
b9ce00
|
454 |
|
1cb30e
|
455 |
.. _Jinja2: http://jinja.pocoo.org/docs/dev/ |
e85845
|
456 |
.. _pyramid_jinja2: |
19d341
|
457 |
https://docs.pylonsproject.org/projects/pyramid-jinja2/en/latest/ |
b9ce00
|
458 |
|
MM |
459 |
.. _Mako: http://www.makotemplates.org/ |
e85845
|
460 |
.. _pyramid_mako: |
19d341
|
461 |
https://docs.pylonsproject.org/projects/pyramid-mako/en/latest/ |