Finished docs/templates_python.txt
git-svn-id: http://code.djangoproject.com/svn/django/trunk@628 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
276731d625
commit
cadb6a008d
|
@ -478,10 +478,10 @@ responsible for returning a ``Node`` instance based on the contents of the tag.
|
||||||
|
|
||||||
By convention, the name of each compilation function should start with ``do_``.
|
By convention, the name of each compilation function should start with ``do_``.
|
||||||
|
|
||||||
For example, let's write a template tag that displays the current date/time,
|
For example, let's write a template tag, ``{% current_time %}``, that displays
|
||||||
formatted according to a parameter given in the tag, in `strftime syntax`_.
|
the current date/time, formatted according to a parameter given in the tag, in
|
||||||
It's a good idea to decide the tag syntax before anything else. In our case,
|
`strftime syntax`_. It's a good idea to decide the tag syntax before anything
|
||||||
let's say the tag should be used like this::
|
else. In our case, let's say the tag should be used like this::
|
||||||
|
|
||||||
<p>The time is {% current_time "%Y-%M-%d %I:%M %p" %}.</p>
|
<p>The time is {% current_time "%Y-%M-%d %I:%M %p" %}.</p>
|
||||||
|
|
||||||
|
@ -507,10 +507,11 @@ Notes:
|
||||||
example.
|
example.
|
||||||
|
|
||||||
* ``token.contents`` is a string of the raw contents of the tag. In our
|
* ``token.contents`` is a string of the raw contents of the tag. In our
|
||||||
example, it's ``'current_time "%Y-%M-%d %I:%M %p"'``
|
example, it's ``'current_time "%Y-%M-%d %I:%M %p"'``.
|
||||||
|
|
||||||
* This function raises ``django.core.template.TemplateSyntaxError``, with
|
* This function is responsible for raising
|
||||||
helpful messages, for any syntax error.
|
``django.core.template.TemplateSyntaxError``, with helpful messages, for
|
||||||
|
any syntax error.
|
||||||
|
|
||||||
* The ``TemplateSyntaxError`` exceptions use the ``tag_name`` variable.
|
* The ``TemplateSyntaxError`` exceptions use the ``tag_name`` variable.
|
||||||
Don't hard-code the tag's name in your error messages, because that
|
Don't hard-code the tag's name in your error messages, because that
|
||||||
|
@ -552,6 +553,9 @@ Notes:
|
||||||
|
|
||||||
* The ``render()`` method is where the work actually happens.
|
* The ``render()`` method is where the work actually happens.
|
||||||
|
|
||||||
|
* ``render()`` should never raise ``TemplateSyntaxError`` or any other
|
||||||
|
exception. It should fail silently, just as template filters should.
|
||||||
|
|
||||||
Ultimately, this decoupling of compilation and rendering results in an
|
Ultimately, this decoupling of compilation and rendering results in an
|
||||||
efficient template system, because a template can render multiple context
|
efficient template system, because a template can render multiple context
|
||||||
without having to be parsed multiple times.
|
without having to be parsed multiple times.
|
||||||
|
@ -566,16 +570,16 @@ Finally, use a ``register_tag`` call, as in ``register_filter`` above. Example::
|
||||||
|
|
||||||
``register_tag`` takes two arguments:
|
``register_tag`` takes two arguments:
|
||||||
|
|
||||||
1. The name of the template tag -- a string
|
1. The name of the template tag -- a string.
|
||||||
2. The compilation function -- a Python function (not the name of the
|
2. The compilation function -- a Python function (not the name of the
|
||||||
function as a string)
|
function as a string).
|
||||||
|
|
||||||
Setting a variable in the context
|
Setting a variable in the context
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The above example simply output a value. Generally, it's more flexible if your
|
The above example simply output a value. Generally, it's more flexible if your
|
||||||
template tags set template variables instead of outputting values. That way,
|
template tags set template variables instead of outputting values. That way,
|
||||||
you allow template authors to reuse the values that your template tags create.
|
template authors can reuse the values that your template tags create.
|
||||||
|
|
||||||
To set a variable in the context, just use dictionary assignment on the context
|
To set a variable in the context, just use dictionary assignment on the context
|
||||||
object in the ``render()`` method. Here's an updated version of
|
object in the ``render()`` method. Here's an updated version of
|
||||||
|
@ -597,7 +601,7 @@ Here's how you'd use this new version of the tag::
|
||||||
|
|
||||||
{% current_time "%Y-%M-%d %I:%M %p" %}<p>The time is {{ current_time }}.</p>
|
{% current_time "%Y-%M-%d %I:%M %p" %}<p>The time is {{ current_time }}.</p>
|
||||||
|
|
||||||
But, there's a naive problem with ``CurrentTimeNode2``: The variable name
|
But, there's a problem with ``CurrentTimeNode2``: The variable name
|
||||||
``current_time`` is hard-coded. This means you'll need to make sure your
|
``current_time`` is hard-coded. This means you'll need to make sure your
|
||||||
template doesn't use ``{{ current_time }}`` anywhere else, because the
|
template doesn't use ``{{ current_time }}`` anywhere else, because the
|
||||||
``{% current_time %}`` will blindly overwrite that variable's value. A cleaner
|
``{% current_time %}`` will blindly overwrite that variable's value. A cleaner
|
||||||
|
@ -636,3 +640,73 @@ class, like so::
|
||||||
|
|
||||||
The difference here is that ``do_current_time()`` grabs the format string and
|
The difference here is that ``do_current_time()`` grabs the format string and
|
||||||
the variable name, passing both to ``CurrentTimeNode3``.
|
the variable name, passing both to ``CurrentTimeNode3``.
|
||||||
|
|
||||||
|
Parsing until another block tag
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Template tags can work in tandem. For instance, the standard ``{% comment %}``
|
||||||
|
tag hides everything until ``{% endcomment %}``. To create a template tag such
|
||||||
|
as this, use ``parser.parse()`` in your compilation function.
|
||||||
|
|
||||||
|
Here's how the standard ``{% comment %}`` tag is implemented::
|
||||||
|
|
||||||
|
def do_comment(parser, token):
|
||||||
|
nodelist = parser.parse(('endcomment',))
|
||||||
|
parser.delete_first_token()
|
||||||
|
return CommentNode()
|
||||||
|
|
||||||
|
class CommentNode(template.Node):
|
||||||
|
def render(self, context):
|
||||||
|
return ''
|
||||||
|
|
||||||
|
``parser.parse()`` takes a tuple of names of block tags ''to parse until''. It
|
||||||
|
returns an instance of ``django.core.template.NodeList``, which is a list of
|
||||||
|
all ``Node`` objects that the parser encountered ''before'' it encountered
|
||||||
|
any of the tags named in the tuple.
|
||||||
|
|
||||||
|
In ``"nodelist = parser.parse(('endcomment',))"`` in the above example,
|
||||||
|
``nodelist`` is a list of all nodes between the ``{% comment %}`` and
|
||||||
|
``{% endcomment %}``, not counting ``{% comment %}`` and ``{% endcomment %}``
|
||||||
|
themselves.
|
||||||
|
|
||||||
|
After ``parser.parse()`` is called, the parser hasn't yet "consumed" the
|
||||||
|
``{% endcomment %}`` tag, so the code needs to explicitly call
|
||||||
|
``parser.delete_first_token()``.
|
||||||
|
|
||||||
|
``CommentNode.render()`` simply returns an empty string. Anything between
|
||||||
|
``{% comment %}`` and ``{% endcomment %}`` is ignored.
|
||||||
|
|
||||||
|
Parsing unitl another block tag, and saving contents
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
In the previous example, ``do_comment()`` discarded everything between
|
||||||
|
``{% comment %}`` and ``{% endcomment %}``. Instead of doing that, it's
|
||||||
|
possible to do something with the code between block tags.
|
||||||
|
|
||||||
|
For example, here's a custom template tag, ``{% upper %}``, that capitalizes
|
||||||
|
everything between itself and ``{% endupper %}``.
|
||||||
|
|
||||||
|
Usage::
|
||||||
|
|
||||||
|
{% upper %}This will appear in uppercase, {{ your_name }}.{% endupper %}
|
||||||
|
|
||||||
|
As in the previous example, we'll use ``parser.parse()``. But this time, we
|
||||||
|
pass the resulting ``nodelist`` to the ``Node``::
|
||||||
|
|
||||||
|
def do_upper(parser, token):
|
||||||
|
nodelist = parser.parse(('endupper',))
|
||||||
|
parser.delete_first_token()
|
||||||
|
return UpperNode(nodelist)
|
||||||
|
|
||||||
|
class UpperNode(template.Node):
|
||||||
|
def __init__(self, nodelist):
|
||||||
|
self.nodelist = nodelist
|
||||||
|
def render(self, context):
|
||||||
|
output = self.nodelist.render(context)
|
||||||
|
return output.upper()
|
||||||
|
|
||||||
|
The only new concept here is the ``self.nodelist.render(context)`` in
|
||||||
|
``UpperNode.render()``.
|
||||||
|
|
||||||
|
For more examples of complex rendering, see the source code for ``{% if %}``,
|
||||||
|
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``.
|
||||||
|
|
Loading…
Reference in New Issue