Templates ========= A :term:`template` is a file on disk which can be used to render dynamic data provided by a :term:`view`, usually surrounded by information that is static. :mod:`repoze.bfg` offers a number of ways to perform templating tasks "out of the box", and provides alternative templating language support via add-on "bindings" packages. .. _chameleon_zpt_templates: Templating With :term:`Chameleon` ZPT Page Templates ---------------------------------------------------- Like :term:`Zope`, :mod:`repoze.bfg` uses Zope Page Templates (:term:`ZPT`) as its default and best-supported templating language. However, :mod:`repoze.bfg` uses a different implementation of the :term:`ZPT` specification than Zope does: the :term:`Chameleon` :term:`chameleon.zpt` templating engine. This templating engine complies largely with the `Zope Page Template `_ template specification, however it is significantly faster. .. note:: The language definition documentation for Chameleon ZPT-style templates is available from `the Chameleon website `_. See its `documentation `_ for the Chameleon ZPT language specification. Given that there is a :term:`chameleon.zpt` template named ``foo.pt`` in a directory in your application named ``templates``, you can render the template from a view like so: .. code-block:: python :linenos: from repoze.bfg.chameleon_zpt import render_template_to_response def sample_view(context, request): return render_template_to_response('templates/foo.pt', foo=1, bar=2) The first argument to ``render_template_to_response`` shown above (and its sister function ``render_template``, not shown, which just returns a string body) is the template *path*. In the example above, the path ``templates/foo.pt`` is *relative*. Relative to what, you ask? Relative to the directory in which the ``views.py`` file which names it lives, which is usually the :mod:`repoze.bfg` application's :term:`package` directory. Although a path is usually just a simple relative pathname, a path passed to ``render_template_to_response`` can be absolute, starting with a slash on UNIX or a drive letter prefix on Windows. The path can alternately be a :term:`resource` "specification" in the form ``some.dotted.package_name:relative/path``, making it possible to address template resources which live in another package. ``render_template_to_response`` always returns a Response object which has a *status code* of ``200 OK`` and a *content-type* of ``text-html``. If you need more control over the status code and content-type, either set attributes on the response that this function returns or use the ``render_template`` function instead (see :ref:`chameleon_zpt_module` for the details), which also renders a ZPT template but returns a string instead of a Response. You can use the string manually as a response body. Here's an example of using ``render_template``: .. code-block:: python :linenos: from repoze.bfg.chameleon_zpt import render_template from webob import Response def sample_view(context, request): result = render_template('templates/foo.pt', foo=1, bar=2) response = Response(result) response.content_type = 'text/plain' return response Here's an example of using ``render_template_to_response`` but changing the content-type and status: .. code-block:: python :linenos: from repoze.bfg.chameleon_zpt import render_template_to_response def sample_view(context, request): response = render_template_to_response('templates/foo.pt', foo=1, bar=2) response.content_type = 'text/plain' response.status_int = 204 return response A Sample Template ~~~~~~~~~~~~~~~~~ Here's what a simple :term:`chameleon.zpt` template used under :mod:`repoze.bfg` might look like: .. code-block:: xml :linenos: ${project} Application

Welcome to ${project}, an application generated by the repoze.bfg web application framework.

Note the use of :term:`Genshi` -style ``${replacements}`` above. This is one of the ways that :term:`chameleon.zpt` differs from standard ZPT. The above template expects to find a ``project`` key in the set of keywords passed in to it via ``render_template`` or ``render_template_to_response``. Typical ZPT attribute-based syntax (e.g. ``tal:content`` and ``tal:replace``) also works in these templates. Using ZPT Macros in :mod:`repoze.bfg` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unlike Zope "browser views", :mod:`repoze.bfg` doesn't make any names (such as ``context`` or ``view``) available to :term:`chameleon.zpt` templates by default. Instead, it expects you to pass all the names you need into the template. One of the common needs in ZPT-based template is to one template's "macros" from within a different template. In Zope, this is typically handled by retrieving the template from the ``context``. To do the same thing in :mod:`repoze.bfg`, you need to make the macro template itself available to the rendered template by passing template in which the macro is defined (or even the macro itself) into the rendered template. To make a macro available to the rendered template, you can retrieve a different template using the ``get_template`` API, and pass it in to the template being rendered. For example: .. code-block:: python :linenos: from repoze.bfg.chameleon_zpt import render_template_to_response from repoze.bfg.chameleon_zpt import get_template def my_view(context, request): main = get_template('templates/master.pt') return render_template_to_response('templates/mytemplate.pt', main=main) Where ``templates/master.pt`` might look like so: .. code-block:: xml :linenos:

Hello Fred!

And ``templates/mytemplate.pt`` might look like so: .. code-block:: xml :linenos: Chris .. _chameleon_text_templates: Templating with :term:`Chameleon` Text Templates ------------------------------------------------ :mod:`repoze.bfg` also allows for the use of templates which are composed entirely of non-XML text via :term:`Chameleon`. To do so, you can create templates that are entirely composed of text except for ``${name}`` -style substitution points. Here's an example usage of a Chameleon text template. Create a file on disk named ``text.txt`` in your project's ``templates`` directory with the following contents:: Hello, ${name}! Then in your project's ``views.py`` module, you can create a view which renders this template: .. code-block:: python :linenos: from repoze.bfg.chameleon_text import render_template_to_response def text_view(context, request): return render_template_to_response('templates/text.txt', name='World') The Chameleon text rendering API is a wholesale mirror of the Chameleon text ZPT rendering API, it's just imported from another place; see :ref:`chameleon_text_module` for the API description. Side Effects of Rendering a Chameleon Template ---------------------------------------------- When a Chameleon template is rendered from a file, the templating engine writes a file in the same directory as the template file itself as a kind of cache, in order to do less work the next time the template needs to be read from disk. When using ``chameleon.core`` version 1.0b32 and lower, this filename is ``.cache``. When using ``chameleon.core`` version 1.0b33 and higher or the ``Chameleon`` (uppercase-C) package, this filename is ``.py``. If you see "strange" ``.py`` or ``.cache`` files showing up in your ``templates`` directory, it is due to this feature. If you're using a version control system such as Subversion, you should cause it to ignore these files. Here's the contents of my ``svn propedit svn:ignore .`` in each of my ``templates`` directories. (Note that I always name my Chameleon ZPT template files with a ``.pt`` extension, so that this pattern works): .. code-block:: bash :linenos: *.cache *.pt.py .. _reload_templates_section: Automatically Reloading Templates --------------------------------- It's often convenient to see changes you make to a template file appear immediately without needing to restart the application process. :mod:`repoze.bfg` allows you configure your application development environment so that a change to a template will be automatically detected, and the template will be reloaded on the next rendering. .. warning:: auto-template-reload behavior is not recommended for production sites as it slows rendering slightly; it's usually only desirable during development. In order to turn on automatic reloading of templates, you can use an environment variable setting or a configuration file setting. To use an environment variable, start your application under a shell using the ``BFG_RELOAD_TEMPLATES`` environment variable set to ``1``, For example:: $ BFG_RELOAD_TEMPLATES=1 bin/paster serve myproject.ini To use a setting in the the application ``.ini`` file for the same purpose, set the ``reload_templates`` key to ``true`` within the application's configuration section, e.g.:: [app:main] use = egg:MyProject#app reload_templates = true :term:`Chameleon` Template Internationalization ----------------------------------------------- See `the internationalization chapter `_ of the Chameleon documentation for information about supporting internationalized units of text within Chameleon templates. Templating with other Templating Languages ------------------------------------------ Because :term:`view` functions are typically the only code in :mod:`repoze.bfg` that need to know anything about templates, and because view functions are very simple Python, you can use whatever templating system you're most comfortable with within :mod:`repoze.bfg`. Install the templating system, import its API functions into your views module, use those APIs to generate a string, then return that string as the body of a :term:`WebOb` ``Response`` object. Assuming you have `Mako `_ installed, here's an example of using Mako from within a :mod:`repoze.bfg` :term:`view`: .. code-block:: python :linenos: from mako.template import Template from webob import Response def make_view(context, request): template = Template(filename='/templates/template.mak') result = template.render(name=context.name) response = Response(result) return response .. note:: It's reasonably easy to write custom templating system binding packages for use under :mod:`repoze.bfg`. See :ref:`available_template_system_bindings` for example packages. Note that if you use third-party templating languages without cooperating BFG bindings, the auto-template-reload strategy explained in :ref:`reload_templates_section` will not be available, nor will the template resource overriding capability explained in :ref:`overriding_resources_section` be available. .. _available_template_system_bindings: Available Add-On Template System Bindings ----------------------------------------- :mod:`repoze.bfg.xslt` is an add-on which provides XSL template bindings. It lives in the Repoze Subversion repository at `http://svn.repoze.org/repoze.bfg.xslt `_. :mod:`repoze.bfg.chameleon_genshi` package is an add-on which provides Chameleon Genshi-style template support. It lives in the Repoze Subversion repository at `http://svn.repoze.org/repoze.bfg.chameleon_genshi `_. Jinja2 template bindings are available for :mod:`repoze.bfg` in the :mod:`repoze.bfg.jinja2` package. It lives in the Repoze Subversion repository at `http://svn.repoze.org/repoze.bfg.jinja2 `_. Courtesy of Carlos de la Guardia, bindings for the Zope ``zope.pagetemplate`` package ("old TAL") are available from `http://svn.repoze.org/repoze.bfg.zopepagetemplate/ `_.