From 096ad32c845f850278b942d087e607dc4311b5f9 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Mon, 5 Sep 2005 23:38:46 +0000 Subject: [PATCH] Added docs/templates_python.txt, which isn't finished yet git-svn-id: http://code.djangoproject.com/svn/django/trunk@623 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- docs/templates.txt | 8 +- docs/templates_python.txt | 275 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 279 insertions(+), 4 deletions(-) create mode 100644 docs/templates_python.txt diff --git a/docs/templates.txt b/docs/templates.txt index 89d9eacda8..e4072b8e44 100644 --- a/docs/templates.txt +++ b/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 ease. It's designed to feel comfortable to those used to working with HTML. If @@ -45,7 +45,7 @@ explained later in this document.:: 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 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. What's a variable? diff --git a/docs/templates_python.txt b/docs/templates_python.txt new file mode 100644 index 0000000000..36ffcbffa3 --- /dev/null +++ b/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 + + +.. 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 +---------------------------- +