Documented the simple_tag and inclusion_tag functions that make writing certain

types of template tags easier.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@2941 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2006-05-19 02:02:34 +00:00
parent e6ee971498
commit 026d8c6f08
1 changed files with 158 additions and 0 deletions

View File

@ -743,6 +743,164 @@ Python 2.4 and above::
If you leave off the ``name`` argument, as in the second example above, Django
will use the function's name as the tag name.
Shortcut for simple tags
~~~~~~~~~~~~~~~~~~~~~~~~
Many template tags take a single argument -- a string or a template variable
reference -- and return a string after doing some processing based solely on
the input argument and some external information. For example, the
``current_time`` tag we wrote above is of this variety: we give it a format
string, it returns the time as a string.
To ease the creation of the types of tags, Django provides a helper function,
``simple_tag``. This function, which is a method of
``django.template.Library``, takes a function that accepts one argument, wraps
it in a ``render`` function and the other necessary bits mentioned above and
registers it with the template system.
Our earlier ``current_time`` function could thus be written like this::
# This version of do_current_time takes only a single argument and returns
# a string.
def do_current_time(token):
try:
# Splitting by None == splitting by spaces.
tag_name, format_string = token.contents.split(None, 1)
except ValueError:
raise template.TemplateSyntaxError, "%r tag requires an argument" % token.contents[0]
if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
return datetime.datetime.now().strftime(self.format_string[1:-1])
register.simple_tag(do_current_time)
In Python 2.4, the decorator syntax also works::
@simple_tag
def do_current_time(token):
...
Inclusion tags
~~~~~~~~~~~~~~
Another type of template tag that is sometimes useful is when you want to
display some data that is computed at render time in a template fragment. For
example, in Django's admin interface, there is a line of buttons along the
bottom of the `create/edit record` screen. These buttons always look the same,
but the link targets change depending upon the object being edited. So they
are a perfect example for using a small template that is filled in with
details from the current object. To save typing, it would also be nice if we
could wrap this whole display up in a single tag (in the admin templates this
is the ``submit_row`` tag).
We call these sorts of tags `inclusion tags`. In your template, you pass in
any appropriate arguments and the tag uses those arguments, together with the
current context to render a template and include the result in the output.
Writing inclusion tags is probably best demonstrated by example. We will write
a tag that outputs a list of choices for a Poll object, such as was created in
the tutorials_. We will use this tag like this::
{{ show_results poll }}
and the output will be something like this::
<ul>
<li>First choice</li>
<li>Second choice</li>
<li>Third choice</li>
</ul>
First, we define the function which takes the argument and produces a
dictionary of data for the result. The important point here is we only need to
return a dictionary, not anything more complex. This will be used to substitue
for values in the template fragment, just as when templates are used
elsewhere.
::
def show_results(poll):
choices = poll.choice_set.all()
return {'choices': choices}
We also need to create the template that is used to render the output. This
template is a fixed feature of the tag: the tag writer specifies it, not the
template designer. In our case, the template is very simple::
<ul>
{% for choice in choices %}
<li> {{ choice }} </li>
{% endfor %}
</ul>
Now we can create the inclusion tag. Suppose the above template is in a file
called ``results.html`` in a directory that is searched by the template
loader. We register our new tag similarly to a normal tag.
::
# Here, register is a django.template.Library instance, as before
register.inclusion_tag('results.html')(show_results)
As always, Python 2.4 decorator syntax works as well, so we could have
written
::
@inclusion_tag('results.html')
def show_results(poll):
...
when first creating the function.
In some cases, an inclusion tag might require a large number of arguments to
display itself properly. In essence, it would depend largely on the current
context it was being rendered with. We can make these sorts of tags easier to
write by telling the ``inclusion_tag`` function that the whole context
should be passed in as an argument to the function. This will be done
invisibly as far as the template tag user is concerned: they will not need to
do anything to pass in the context.
For example, suppose we are writing an inclusion tag that will always be used
in a context that contains ``home_link`` and ``home_title`` variables that
point back to the main page. We can write a tag that is used like this::
{{ jump_link }}
and renders this::
Jump directly to <a href="http://example.com/home">Home</a>
The tag function is almost as simple as before. This time it takes no
arguments except the ``context`` (and the parameter `must` be called
``context`` in this case; the special parameter named is used internally by
Django to fill in the values correctly).
::
# The first argument *must* be called "context" here.
def jump_link(context):
return {
'link': context['home_link'],
'title': context['home_title'],
}
Our template is very simple again::
Jump directly to <a href="{{ link }}">{{ title }}</a>.
Assuming the template is in a file called ``link.html``, we register this new
tag as follows::
register.inclusion_tag('link.html', takes_context = True)(jump_link)
The ``takes_context`` parameter here defaults to *False*. When it is set to
*True*, our tag is passed the implicit context as in this example. That is the
only difference between this case and our previous use of ``inclusion_tag``.
.. _tutorials: http://www.djangoproject.com/documentation/tutorial1/#creating-models
Setting a variable in the context
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~