diff options
| author | Aymeric Augustin <aymeric.augustin@m4x.org> | 2015-01-03 23:05:34 +0100 |
|---|---|---|
| committer | Aymeric Augustin <aymeric.augustin@m4x.org> | 2015-01-10 20:16:19 +0100 |
| commit | ee8d5b91e94f6920f846512c978b703f62545ca8 (patch) | |
| tree | 3c6d252d4621220afa117f2e71d5a0b82311cc51 /docs/topics | |
| parent | 6c392bb2c00a7779a0f2a485bfdeea456ed39181 (diff) | |
Wrote main documentation for templates.
Diffstat (limited to 'docs/topics')
| -rw-r--r-- | docs/topics/http/shortcuts.txt | 4 | ||||
| -rw-r--r-- | docs/topics/templates.txt | 653 |
2 files changed, 654 insertions, 3 deletions
diff --git a/docs/topics/http/shortcuts.txt b/docs/topics/http/shortcuts.txt index d3971fb711..d31572dd4d 100644 --- a/docs/topics/http/shortcuts.txt +++ b/docs/topics/http/shortcuts.txt @@ -124,8 +124,8 @@ Required arguments ``template_name`` The full name of a template to use or sequence of template names. If a sequence is given, the first template that exists will be used. See the - :ref:`template loader documentation <ref-templates-api-the-python-api>` - for more information on how templates are found. + :ref:`template loading documentation <template-loading>` for more + information on how templates are found. Optional arguments ------------------ diff --git a/docs/topics/templates.txt b/docs/topics/templates.txt index 1b53a9d4f5..30e1b9b011 100644 --- a/docs/topics/templates.txt +++ b/docs/topics/templates.txt @@ -1 +1,652 @@ -TODO - explain multiple template engines and the django template language +========= +Templates +========= + +.. module:: django.template + :synopsis: Django's template system + +Being a web framework, Django needs a convenient way to generate HTML +dynamically. The most common approach relies on templates. A template contains +the static parts of the desired HTML output as well as some special syntax +describing how dynamic content will be inserted. For a hands-on example of +creating HTML pages with templates, see :doc:`Tutorial 3 </intro/tutorial03>`. + +A Django project can be configured with one or several template engines (or +even zero if you don't use templates). Django ships built-in backends for its +own template system, creatively called the Django template language (DTL), and +for the popular alternative Jinja2_. Backends for other template languages may +be available from third-parties. + +Django defines a standard API for loading and rendering templates regardless +of the backend. Loading consists of finding the template for a given identifier +and preprocessing it, usually compiling it to an in-memory representation. +Rendering means interpolating the template with context data and returning the +resulting string. + +The :doc:`Django template language </ref/templates/language>` is Django's own +template system. Until Django 1.8 it was the only built-in option available. +It's a good template library even though it's fairly opinionated and sports a +few idiosyncrasies. If you don't have a pressing reason to choose another +backend, you should use the DTL, especially if you're writing a pluggable +application and you intend to distribute templates. Django's contrib apps that +include templates, like :doc:`django.contrib.admin </ref/contrib/admin/index>`, +use the DTL. + +For historical reasons, both the generic support for template engines and the +implementation of the Django template language live in the ``django.template`` +namespace. + +.. _template-engines: + +Support for template engines +============================ + +.. versionadded:: 1.8 + + Support for multiple template engines and the :setting:`TEMPLATES` setting + were added in Django 1.8. + +Configuration +------------- + +Templates engines are configured with the :setting:`TEMPLATES` setting. It's a +list of configurations, one for each engine. The default value is empty. The +``settings.py`` generated by the :djadmin:`startproject` command defines a +more useful value:: + + TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + # ... some options here ... + }, + }, + ] + +:setting:`BACKEND <TEMPLATES-BACKEND>` is a dotted Python path to a template +engine class implementing Django's template backend API. The built-in backends +are :class:`django.template.backends.django.DjangoTemplates` and +:class:`django.template.backends.jinja2.Jinja2`. + +Since most engines load templates from files, the top-level configuration for +each engine contains two common settings: + +* :setting:`DIRS <TEMPLATES-DIRS>` defines a list of directories where the + engine should look for template source files, in search order. +* :setting:`APP_DIRS <TEMPLATES-APP_DIRS>` tells whether the engine should + look for templates inside installed applications. Each backend defines a + conventional name for the subdirectory inside applications where its + templates should be stored. + +While uncommon, it's possible to configure several instances of the same +backend with different options. In that case you should define a unique +:setting:`NAME <TEMPLATES-NAME>` for each engine. + +:setting:`OPTIONS <TEMPLATES-OPTIONS>` contains backend-specific settings. + +Usage +----- + +.. _template-loading: + +.. module:: django.template.loader + +The ``django.template.loader`` module defines two functions to load templates. + +.. function:: get_template(template_name[, dirs][, using]) + + This function loads the template with the given name and returns a + ``Template`` object. + + The exact type of the return value depends on the backend that loaded the + template. Each backend has its own ``Template`` class. + + ``get_template()`` tries each template engine in order until one succeeds. + If the template cannot be found, it raises + :exc:`~django.template.TemplateDoesNotExist`. If the template is found but + contains invalid syntax, it raises + :exc:`~django.template.TemplateSyntaxError`. + + How templates are searched and loaded depends on each engine's backend and + configuration. + + If you want to restrict the search to a particular template engine, pass + the engine's :setting:`NAME <TEMPLATES-NAME>` in the ``using`` argument. + + .. versionchanged:: 1.7 + + The ``dirs`` parameter was added. + + .. deprecated:: 1.8 + + The ``dirs`` parameter was deprecated. + + .. versionchanged:: 1.8 + + The ``using`` parameter was added. + + .. versionchanged:: 1.8 + + ``get_template()`` returns a backend-dependent ``Template`` instead + of a :class:`django.template.Template`. + +.. function:: select_template(template_name_list[, dirs][, using]) + + ``select_template()`` is just like ``get_template()``, except it takes a + list of template names. It tries each name in order and returns the first + template that exists. + + .. versionchanged:: 1.7 + + The ``dirs`` parameter was added. + + .. deprecated:: 1.8 + + The ``dirs`` parameter was deprecated. + + .. versionchanged:: 1.8 + + The ``using`` parameter was added. + + .. versionchanged:: 1.8 + + ``select_template()`` returns a backend-dependent ``Template`` instead + of a :class:`django.template.Template`. + +.. currentmodule:: django.template + +If loading a template fails, the following two exceptions, defined in +``django.template``, may be raised: + +.. exception:: TemplateDoesNotExist + + This exception is raised when a template cannot be found. + +.. exception:: TemplateSyntaxError + + This exception is raised when a template was found but contains errors. + +``Template`` objects returned by ``get_template()`` and ``select_template()`` +must provide a ``render()`` method with the following signature: + +.. currentmodule:: django.template.backends.base + +.. method:: Template.render(context=None, request=None) + + Renders this template with a given context. + + If ``context`` is provided, it must be a :class:`dict`. If it isn't + provided, the engine will render the template with an empty context. + + If ``request`` is provided, it must be an :class:`~django.http.HttpRequest`. + Then the engine must make it, as well as the CSRF token, available in the + template. How this is achieved is up to each backend. + +Here's an example of the search algorithm. For this example the +:setting:`TEMPLATES` setting is:: + + TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + '/home/html/example.com', + '/home/html/default', + ], + }, + { + 'BACKEND': 'django.template.backends.jinja2.Jinja2', + 'DIRS': [ + '/home/html/jinja2', + ], + }, + ] + +If you call ``get_template('story_detail.html')``, here are the files Django +will look for, in order: + +* ``/home/html/example.com/story_detail.html`` (``'django'`` engine) +* ``/home/html/default/story_detail.html`` (``'django'`` engine) +* ``/home/html/jinja2/story_detail.html`` (``'jinja2'`` engine) + +If you call ``select_template(['story_253_detail.html', 'story_detail.html'])``, +here's what Django will look for: + +* ``/home/html/example.com/story_253_detail.html`` (``'django'`` engine) +* ``/home/html/default/story_253_detail.html`` (``'django'`` engine) +* ``/home/html/jinja2/story_253_detail.html`` (``'jinja2'`` engine) +* ``/home/html/example.com/story_detail.html`` (``'django'`` engine) +* ``/home/html/default/story_detail.html`` (``'django'`` engine) +* ``/home/html/jinja2/story_detail.html`` (``'jinja2'`` engine) + +When Django finds a template that exists, it stops looking. + +.. admonition:: Tip + + You can use :func:`~django.template.loader.select_template()` for flexible + template loading. For example, if you've written a news story and want + some stories to have custom templates, use something like + ``select_template(['story_%s_detail.html' % story.id, + 'story_detail.html'])``. That'll allow you to use a custom template for an + individual story, with a fallback template for stories that don't have + custom templates. + +It's possible -- and preferable -- to organize templates in subdirectories +inside each directory containing templates. The convention is to make a +subdirectory for each Django app, with subdirectories within those +subdirectories as needed. + +Do this for your own sanity. Storing all templates in the root level of a +single directory gets messy. + +To load a template that's within a subdirectory, just use a slash, like so:: + + get_template('news/story_detail.html') + +Using the same :setting:`TEMPLATES` option as above, this will attempt to load +the following templates: + +* ``/home/html/example.com/news/story_detail.html`` (``'django'`` engine) +* ``/home/html/default/news/story_detail.html`` (``'django'`` engine) +* ``/home/html/jinja2/news/story_detail.html`` (``'jinja2'`` engine) + +.. currentmodule:: django.template.loader + +In addition, to cut down on the repetitive nature of loading and rendering +templates, Django provides a shortcut function which automates the process. + +.. function:: render_to_string(template_name[, context][, context_instance][, request][, using]) + + ``render_to_string()`` loads a template like :func:`get_template` and + calls its ``render()`` method immediately. It takes the following + arguments. + + ``template_name`` + The name of the template to load and render. If it's a list of template + names, Django uses :func:`select_template` instead of + :func:`get_template` to find the template. + + ``context`` + A :class:`dict` to be used as the template's context for rendering. + + .. versionchanged:: 1.8 + + The ``context`` argument used to be called ``dictionary``. That name + is deprecated in Django 1.8 and will be removed in Django 2.0. + + ``context`` is now optional. An empty context will be used if it + isn't provided. + + ``context_instance`` + An instance of :class:`~django.template.Context` or a subclass (e.g., an + instance of :class:`~django.template.RequestContext`) to use as the + template's context. + + .. deprecated:: 1.8 + + The ``context_instance`` argument is deprecated. Use ``context`` and + if needed ``request``. + + ``request`` + An optional :class:`~django.http.HttpRequest` that will be available + during the template's rendering process. + + .. versionadded:: 1.8 + + The ``request`` argument was added. + +See also the :func:`~django.shortcuts.render()` and +:func:`~django.shortcuts.render_to_response()` shortcuts, which call +:func:`render_to_string()` and feed the result into an +:class:`~django.http.HttpResponse` suitable for returning from a view. + +Finally, you can use configured engines directly: + +.. data:: engines + + Template engines are available in ``django.template.engines``:: + + from django.template import engines + + django_engine = engines['django'] + template = django_engine.from_string("Hello {{ name }}!") + + The lookup key — ``'django'`` in this example — is the engine's + :setting:`NAME <TEMPLATES-NAME>`. + +.. module:: django.template.backends + +Built-in backends +----------------- + +.. module:: django.template.backends.django + +.. class:: DjangoTemplates + +Set :setting:`BACKEND <TEMPLATES-BACKEND>` to +``'django.template.backends.django.DjangoTemplates'`` to configure a Django +template engine. + +When :setting:`APP_DIRS <TEMPLATES-APP_DIRS>` is ``True``, ``DjangoTemplates`` +engines look for templates in the ``templates`` subdirectory of installed +applications. This generic name was kept for backwards-compatibility. + +``DjangoTemplates`` engines accept the following :setting:`OPTIONS +<TEMPLATES-OPTIONS>`: + +* ``'allowed_include_roots'``: a list of strings representing allowed prefixes + for the ``{% ssi %}`` template tag. This is a security measure, so that + template authors can't access files that they shouldn't be accessing. + + For example, if ``'allowed_include_roots'`` is ``['/home/html', + '/var/www']``, then ``{% ssi /home/html/foo.txt %}`` would work, but ``{% + ssi /etc/passwd %}`` wouldn't. + + It defaults to an empty list. + + .. deprecated:: 1.8 + + ``allowed_include_roots`` is deprecated because the {% ssi %} tag is + deprecated. + +* ``'context_processors'``: a list of dotted Python paths to callables that + are used to populate the context when a template is rendered with a request. + These callables take a request object as their argument and return a + :class:`dict` of items to be merged into the context. + + It defaults to an empty list. + + See :class:`~django.template.RequestContext` for more information. + +* ``'debug'``: a boolean that turns on/off template debug mode. If it is + ``True``, the fancy error page will display a detailed report for any + exception raised during template rendering. This report contains the + relevant snippet of the template with the appropriate line highlighted. + + It defaults to the value of the :setting:`TEMPLATE_DEBUG` setting. The + setting is convenient for toggling template debug mode globally rather than + on a per-engine basis. + +* ``'loaders'``: a list of dotted Python paths to template loader classes. + Each ``Loader`` class knows how to import templates from a particular + source. Optionally, a tuple can be used instead of a string. The first item + in the tuple should be the ``Loader`` class name, and subsequent items are + passed to the ``Loader`` during initialization. + + The default depends on the values of :setting:`DIRS <TEMPLATES-DIRS>` and + :setting:`APP_DIRS <TEMPLATES-APP_DIRS>`. + + See :ref:`template-loaders` for details. + +* ``'string_if_invalid'``: the output, as a string, that the template system + should use for invalid (e.g. misspelled) variables. + + It defaults to an empty string. + + See :ref:`invalid-template-variables` for details. + +* ``'file_charset'``: the charset used to read template files on disk. + + It defaults to the value of :setting:`FILE_CHARSET`. + +.. module:: django.template.backends.jinja2 + +.. class:: Jinja2 + +Set :setting:`BACKEND <TEMPLATES-BACKEND>` to +``'django.template.backends.jinja2.Jinja2'`` to configure a Jinja2_ engine. + +When :setting:`APP_DIRS <TEMPLATES-APP_DIRS>` is ``True``, ``Jinja2`` engines +look for templates in the ``jinja2`` subdirectory of installed applications. + +The most important entry in :setting:`OPTIONS <TEMPLATES-OPTIONS>` is +``'environment'``. It's a dotted Python path to a callable returning a Jinja2 +environment. It defaults to ``'jinja2.Environment'``. Django invokes that +callable and passes other options as keyword arguments. Furthermore, Django +adds defaults that differ from Jinja2's for a few options: + +* ``'autoescape'``: ``True`` +* ``'loader'``: a loader configured for :setting:`DIRS <TEMPLATES-DIRS>` and + :setting:`APP_DIRS <TEMPLATES-APP_DIRS>` +* ``'auto_reload'``: ``settings.DEBUG`` +* ``'undefined'``: ``DebugUndefined if settings.DEBUG else Undefined`` + +Custom backends +--------------- + +Here's how to implement a custom template backend in order to use another +template system. A template backend is a class that inherits +``django.template.backends.base.BaseEngine``. It must implement +``get_template()`` and optionally ``from_string()``. Here's an example for a +fictional ``foobar`` template library:: + + from django.template import TemplateDoesNotExist, TemplateSyntaxError + from django.template.backends.base import BaseEngine + from django.template.backends.utils import csrf_input_lazy, csrf_token_lazy + + import foobar + + + class FooBar(BaseEngine): + + # Name of the subdirectory containing the templates for this engine + # inside an installed application. + app_dirname = 'foobar' + + def __init__(self, params): + params = params.copy() + options = params.pop('OPTIONS').copy() + super(FooBar, self).__init__(params) + + self.engine = foobar.Engine(**options) + + + def from_string(self, template_code): + try: + return Template(self.engine.from_string(template_code)) + except foobar.TemplateCompilationFailed as exc: + raise TemplateSyntaxError(exc.args) + + def get_template(self, template_name): + try: + return Template(self.engine.get_template(template_name)) + except foobar.TemplateNotFound as exc: + raise TemplateDoesNotExist(exc.args) + except foobar.TemplateCompilationFailed as exc: + raise TemplateSyntaxError(exc.args) + + + class Template(object): + + def __init__(self, template): + self.template = template + + def render(self, context=None, request=None): + if context is None: + context = {} + if request is not None: + context['request'] = request + context['csrf_input'] = csrf_input_lazy(request) + context['csrf_token'] = csrf_token_lazy(request) + return self.template.render(context) + +See `DEP 182`_ for more information. + +.. currentmodule:: django.template + +.. _template-language-intro: + +The Django template language +============================ + +.. highlightlang:: html+django + +Syntax +------ + +.. admonition:: About this section + + This is an overview of the Django template language's syntax. For details + see the :doc:`language syntax reference </ref/templates/language>`. + +A Django template is simply a text document or a Python string marked-up using +the Django template language. Some constructs are recognized and interpreted +by the template engine. The main ones are variables and tags. + +A template is rendered with a context. Rendering replaces variables with their +values, which are looked up in the context, and executes tags. Everything else +is output as is. + +The syntax of the Django template language involves four constructs. + +Variables +~~~~~~~~~ + +A variable outputs a value from the context, which is a dict-like object +mapping keys to values. + +Variables are surrounded by ``{{`` and ``}}`` like this:: + + My first name is {{ first_name }}. My last name is {{ last_name }}. + +With a context of ``{'first_name': 'John', 'last_name': 'Doe'}``, this +template renders to:: + + My first name is John. My last name is Doe. + +Dictionary lookup, attribute lookup and list-index lookups are implemented +with a dot notation:: + + {{ my_dict.key }} + {{ my_object.attribute }} + {{ my_list.0 }} + +If a variable resolves to a callable, the template system will call it with no +arguments and use its result instead of the callable. + +Tags +~~~~ + +Tags provide arbitrary logic in the rendering process. + +This definition is deliberately vague. For example, a tag can output content, +serve as a control structure e.g. an "if" statement or a "for" loop, grab +content from a database, or even enable access to other template tags. + +Tags are surrounded by ``{%`` and ``%}`` like this:: + + {% csrf_token %} + +Most tags accept arguments:: + + {% cycle 'odd' 'even' %} + +Some tags require beginning and ending tags:: + + {% if user.is_authenticated %}Hello, {{ user.username }}.{% endif %} + +A :ref:`reference of built-in tags <ref-templates-builtins-tags>` is +available as well as :ref:`instructions for writing custom tags +<howto-writing-custom-template-tags>`. + +Filters +~~~~~~~ + +Filters transform the values of variables and tag arguments. + +They look like this:: + + {{ django|title }} + +With a context of ``{'django': 'the web framework for perfectionists with +deadlines'}``, this template renders to:: + + The Web Framework For Perfectionists With Deadlines + +Some filters take an argument:: + + {{ my_date|date:"Y-m-d" }} + +A :ref:`reference of built-in filters <ref-templates-builtins-filters>` is +available as well as :ref:`instructions for writing custom filters +<howto-writing-custom-template-filters>`. + +Comments +~~~~~~~~ + +Comments look like this:: + + {# this won't be rendered #} + +A :ttag:`{% comment %} <comment>` tag provides multi-line comments. + +Components +---------- + +.. admonition:: About this section + + This is an overview of the Django template language's APIs. For details + see the :doc:`API reference </ref/templates/api>`. + +Engine +~~~~~~ + +:class:`django.template.Engine` encapsulates an instance of the Django +template system. The main reason for instantiating an +:class:`~django.template.Engine` directly is to use the Django template +language outside of a Django project. + +:class:`django.template.backends.django.DjangoTemplates` is a thin wrapper +adapting :class:`django.template.Engine` to Django's template backend API. + +Template +~~~~~~~~ + +:class:`django.template.Template` represents a compiled template. +Templates are obtained with :meth:`Engine.get_template() +<django.template.Engine.get_template>` or :meth:`Engine.from_string() +<django.template.Engine.from_string>` + +Likewise ``django.template.backends.django.Template`` is a thin wrapper +adapting :class:`django.template.Template` to the common template API. + +Context +~~~~~~~ + +:class:`django.template.Context` holds some metadata in addition to the +context data. It is passed to :meth:`Template.render() +<django.template.Template.render>` for rendering a template. + +:class:`django.template.RequestContext` is a subclass of +:class:`~django.template.Context` that stores the current +:class:`~django.http.HttpRequest` and runs template context processors. + +The common API doesn't have an equivalent concept. Context data is passed in a +plain :class:`dict` and the current :class:`~django.http.HttpRequest` is passed +separately if needed. + +Loaders +~~~~~~~ + +Template loaders are responsible for locating templates, loading them, and +returning :class:`~django.template.Template` objects. + +Django provides several :ref:`built-in template loaders <template-loaders>` +and supports :ref:`custom template loaders <custom-template-loaders>`. + +Context processors +~~~~~~~~~~~~~~~~~~ + +Context processors are functions that receive the current +:class:`~django.http.HttpRequest` as an argument and return a :class:`dict` of +data to be added to the rendering context. + +Their main use is to add common data shared by all templates to the context +without repeating code in every view. + +Django provides many :ref:`built-in context processors <context-processors>`. +Implementing a custom context processor is as simple as defining a function. + +.. _Jinja2: http://jinja.pocoo.org/ +.. _DEP 182: https://github.com/django/deps/blob/master/accepted/0182-multiple-template-engines.rst |
