Skip to content

Commit

Permalink
Added docs/templates_python.txt, which isn't finished yet
Browse files Browse the repository at this point in the history
git-svn-id: http://code.djangoproject.com/svn/django/trunk@623 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
adrianholovaty committed Sep 5, 2005
1 parent e5a8015 commit 096ad32
Show file tree
Hide file tree
Showing 2 changed files with 279 additions and 4 deletions.
8 changes: 4 additions & 4 deletions docs/templates.txt
@@ -1,6 +1,6 @@
============================ ==================================================
The Django template language The Django template language: For template authors
============================ ==================================================


Django's template language is designed to strike a balance between power and Django's template language is designed to strike a balance between power and
ease. It's designed to feel comfortable to those used to working with HTML. If ease. It's designed to feel comfortable to those used to working with HTML. If
Expand Down Expand Up @@ -45,7 +45,7 @@ explained later in this document.::
Why use a text-based template instead of an XML-based one (like Zope's Why use a text-based template instead of an XML-based one (like Zope's
TAL)? We wanted Django's template language to be usable for more than TAL)? We wanted Django's template language to be usable for more than
just XML/HTML templates. At World Online, we use it for e-mails, just XML/HTML templates. At World Online, we use it for e-mails,
Javascript and CSV. You can use the template language for any text-based JavaScript and CSV. You can use the template language for any text-based
format. format.


What's a variable? What's a variable?
Expand Down
275 changes: 275 additions & 0 deletions docs/templates_python.txt
@@ -0,0 +1,275 @@
====================================================
The Django template language: For Python programmers
====================================================

This document explains the Django template system from a technical
perspective -- how it works and how to extend it. If you're just looking for
reference on the language syntax, see
`The Django template language: For template authors`_.

.. _`The Django template language: For template authors`: http://www.djangoproject.com/documentation/templates/

Basics
======

A **template** is a text document, or a normal Python string, that is marked-up
using the Django template language. A template can contain **block tags** or
**variables**.

A **block tag** is a symbol within a template that does something.

This definition is deliberately vague. For example, a block tag can output
content, serve as a control structure (an "if" statement or "for" loop), grab
content from a database or enable access to other template tags.

Block tags are surrounded by ``"{%"`` and ``"%}"``.

Example template with block tags::

{% if is_logged_in %}Thanks for logging in!{% else %}Please log in.{% endif %}

A **variable** is a symbol within a template that outputs a value.

Block tags are surrounded by ``"{{"`` and ``"}}"``.

Example template with variables::

My first name is {{ first_name }}. My last name is {{ last_name }}.

A **context** is a "variable name" -> "variable value" mapping that is passed
to a template.

A template **renders** a context by replacing the variable "holes" with values
from the context and executing all block tags.

Using the template system
=========================

Using the template system in Python is a two-step process:

* First, you compile the raw template code into a ``Template`` object.
* Then, you call the ``render()`` method of the ``Template`` object with a
given context.

Compiling a string
------------------

The easiest way to create a ``Template`` object is by instantiating it
directly. The class lives at ``django.core.template.Template``. The constructor
takes one argument -- the raw template code::

>>> from django.core.template import Template
>>> t = Template("My name is {{ my_name }}.")
>>> print t
<django.core.template.Template instance>

.. admonition:: Behind the scenes

The system only parses your raw template code once -- when you create the
``Template`` object. From then on, it's stored internally as a "node"
structure for performance.

Even the parsing itself is quite fast. Most of the parsing happens via a
single call to a single, short, regular expression.

Rending a context
-----------------

Once you have a compiled ``Template`` object, you can render a context -- or
multiple contexts -- with it. The ``Context`` class lives at
``django.core.template.Context``, and the constructor takes one (optional)
argument: a dictionary mapping variable names to variable values. Call the
``Template`` object's ``render()`` method with the context to "fill" the
template::

>>> from django.core.template import Context, Template
>>> t = Template("My name is {{ my_name }}.")

>>> c = Context({"my_name": "Adrian"})
>>> t.render(c)
"My name is Adrian."

>>> c = Context({"my_name": "Dolores"})
>>> t.render(c)
"My name is Dolores."

Variable names must consist of any letter (A-Z), any digit (0-9), an underscore
or a dot.

Dots have a special meaning in template rendering. A dot in a variable name
signifies **lookup**. Specifically, when the template system encounters a dot
in a variable name, it tries the following lookups, in this order:

* Dictionary lookup. Example: ``foo["bar"]``
* Attribute lookup. Example: ``foo.bar``
* Method call. Example: ``foo.bar()``
* List-index lookup. Example: ``foo[bar]``

The template system uses the first lookup type that works. It's short-circuit
logic.

Here are a few examples::

>>> from django.core.template import Context, Template
>>> t = Template("My name is {{ person.first_name }}.")
>>> d = {"person": {"first_name": "Joe", "last_name": "Johnson"}}
>>> t.render(Context(d))
"My name is Joe."

>>> class PersonClass: pass
>>> p = PersonClass()
>>> p.first_name = "Ron"
>>> p.last_name = "Nasty"
>>> t.render(Context({"person": p}))
"My name is Ron."

>>> class PersonClass2:
... def first_name(self):
... return "Samantha"
>>> p = PersonClass2()
>>> t.render(Context({"person": p}))
"My name is Samantha."

>>> t = Template("The first stooge in the list is {{ stooges.0 }}.")
>>> c = Context({"stooges": ["Larry", "Curly", "Moe"]})
>>> t.render(c)
"The first stooge in the list is Larry."

If a variable doesn't exist, the template system fails silently. The variable
is replaced with an empty string.

>>> t = Template("My name is {{ my_name }}.")
>>> c = Context({"foo": "bar"})
>>> t.render(c)
"My name is ."

Method lookups are slightly more complex than the other lookup types. Here are
some things to keep in mind:

* If, during the method lookup, a method raises an exception, the exception
will be propgated, unless the exception subclasses
``django.core.template.SilentVariableFailure``. If the exception
subclasses ``SilentVariableFailure``, the variable will render as an
empty string. Example::

>>> t = Template("My name is {{ person.first_name }}.")
>>> class PersonClass3:
... def first_name(self):
... raise AssertionError, "foo"
>>> p = PersonClass3()
>>> t.render(Context({"person": p}))
Traceback (most recent call last):
...
AssertionError: foo

>>> from django.core.template import SilentVariableFailure
>>> class SilentAssertionError(SilentVariableFailure): pass
>>> class PersonClass4:
... def first_name(self):
... raise SilentAssertionError, "foo"
>>> p = PersonClass4()
>>> t.render(Context({"person": p}))
"My name is ."

* A method call will only work if the method has no required arguments.
Otherwise, the system will move to the next lookup type (list-index
lookup).

* Obviously, some methods have side effects, and it'd be either foolish or
a security hole to allow the template system to access them.

A good example is the ``delete()`` method on each Django model object.
The template system shouldn't be allowed to do something like this::

I will now delete this valuable data. {{ data.delete }}

To prevent this, set a function attribute ``alters_data`` on the method.
The template system won't execute a method if the method has
``alters_data=True`` set. The dynamically-generated ``delete()`` and
``save()`` methods on Django model objects get ``alters_data=True``
automatically.

Loading templates
-----------------

Generally, you'll store templates in files on your filesystem rather than using
the low-level ``Template`` API yourself. Save templates in a file with an
".html" extension in a directory specified as a **template directory**.

(The ".html" extension is just a required convention. It doesn't mean templates
can only contain HTML. They can contain whatever textual content you want.)

The TEMPLATE_DIRS setting
~~~~~~~~~~~~~~~~~~~~~~~~~

Tell Django what your template directories are by using the ``TEMPLATE_DIRS``
setting in your settings file. This should be set to a list or tuple of strings
that contain full paths to your template directory(ies). Example::

TEMPLATE_DIRS = (
"/home/html/templates/lawrence.com",
"/home/html/templates/default",
)

The Python API
~~~~~~~~~~~~~~

Django has two ways to load templates from files:

``django.core.template_loader.get_template(template_name)``
``get_template`` returns the compiled template (a ``Template`` object) for
the given name. If the template doesn't exist, it raises
``django.core.template.TemplateDoesNotExist``.

``django.core.template_loader.select_template(template_name_list)``
``select_template`` is just like ``get_template``, except it takes a list
of template names. Of the list, it returns the first template that exists.

For example, if you call ``get_template("story_detail")`` and have the above
``TEMPLATE_DIRS`` setting, here are the files Django will look for, in order:

* ``/home/html/templates/lawrence.com/story_detail.html``
* ``/home/html/templates/default/story_detail.html``

If you call ``select_template(["story_253_detail", "story_detail"])``, here's
what Django will look for:

* ``/home/html/templates/lawrence.com/story_253_detail.html``
* ``/home/html/templates/default/story_253_detail.html``
* ``/home/html/templates/lawrence.com/story_detail.html``
* ``/home/html/templates/default/story_detail.html``

When Django finds a template that exists, it stops looking.

.. admonition:: Tip

You can use ``select_template`` for super-flexible "templatability." 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" % story.id, "story_detail"])``.
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.

Using subdirectories
~~~~~~~~~~~~~~~~~~~~

It's possible -- and preferable -- to organize templates in subdirectories of
the template directory. 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")

Extending the template system
=============================

Writing custom template filters
-------------------------------

Writing custom template tags
----------------------------

0 comments on commit 096ad32

Please sign in to comment.