PageRenderTime 40ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/docs/howto/custom-template-tags.txt

https://code.google.com/p/mango-py/
Plain Text | 949 lines | 711 code | 238 blank | 0 comment | 0 complexity | 8de3164fc384b791e25f8cf374f57c0d MD5 | raw file
Possible License(s): BSD-3-Clause
  1. ================================
  2. Custom template tags and filters
  3. ================================
  4. Introduction
  5. ============
  6. Django's template system comes with a wide variety of :doc:`built-in
  7. tags and filters </ref/templates/builtins>` designed to address the
  8. presentation logic needs of your application. Nevertheless, you may
  9. find yourself needing functionality that is not covered by the core
  10. set of template primitives. You can extend the template engine by
  11. defining custom tags and filters using Python, and then make them
  12. available to your templates using the ``{% load %}`` tag.
  13. Code layout
  14. -----------
  15. Custom template tags and filters must live inside a Django app. If they relate
  16. to an existing app it makes sense to bundle them there; otherwise, you should
  17. create a new app to hold them.
  18. The app should contain a ``templatetags`` directory, at the same level as
  19. ``models.py``, ``views.py``, etc. If this doesn't already exist, create it -
  20. don't forget the ``__init__.py`` file to ensure the directory is treated as a
  21. Python package.
  22. Your custom tags and filters will live in a module inside the ``templatetags``
  23. directory. The name of the module file is the name you'll use to load the tags
  24. later, so be careful to pick a name that won't clash with custom tags and
  25. filters in another app.
  26. For example, if your custom tags/filters are in a file called
  27. ``poll_extras.py``, your app layout might look like this::
  28. polls/
  29. models.py
  30. templatetags/
  31. __init__.py
  32. poll_extras.py
  33. views.py
  34. And in your template you would use the following:
  35. .. code-block:: html+django
  36. {% load poll_extras %}
  37. The app that contains the custom tags must be in :setting:`INSTALLED_APPS` in
  38. order for the ``{% load %}`` tag to work. This is a security feature: It allows
  39. you to host Python code for many template libraries on a single host machine
  40. without enabling access to all of them for every Django installation.
  41. There's no limit on how many modules you put in the ``templatetags`` package.
  42. Just keep in mind that a ``{% load %}`` statement will load tags/filters for
  43. the given Python module name, not the name of the app.
  44. To be a valid tag library, the module must contain a module-level variable
  45. named ``register`` that is a ``template.Library`` instance, in which all the
  46. tags and filters are registered. So, near the top of your module, put the
  47. following::
  48. from django import template
  49. register = template.Library()
  50. .. admonition:: Behind the scenes
  51. For a ton of examples, read the source code for Django's default filters
  52. and tags. They're in ``django/template/defaultfilters.py`` and
  53. ``django/template/defaulttags.py``, respectively.
  54. Writing custom template filters
  55. -------------------------------
  56. Custom filters are just Python functions that take one or two arguments:
  57. * The value of the variable (input) -- not necessarily a string.
  58. * The value of the argument -- this can have a default value, or be left
  59. out altogether.
  60. For example, in the filter ``{{ var|foo:"bar" }}``, the filter ``foo`` would be
  61. passed the variable ``var`` and the argument ``"bar"``.
  62. Filter functions should always return something. They shouldn't raise
  63. exceptions. They should fail silently. In case of error, they should return
  64. either the original input or an empty string -- whichever makes more sense.
  65. Here's an example filter definition::
  66. def cut(value, arg):
  67. "Removes all values of arg from the given string"
  68. return value.replace(arg, '')
  69. And here's an example of how that filter would be used:
  70. .. code-block:: html+django
  71. {{ somevariable|cut:"0" }}
  72. Most filters don't take arguments. In this case, just leave the argument out of
  73. your function. Example::
  74. def lower(value): # Only one argument.
  75. "Converts a string into all lowercase"
  76. return value.lower()
  77. Template filters that expect strings
  78. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  79. If you're writing a template filter that only expects a string as the first
  80. argument, you should use the decorator ``stringfilter``. This will
  81. convert an object to its string value before being passed to your function::
  82. from django.template.defaultfilters import stringfilter
  83. @stringfilter
  84. def lower(value):
  85. return value.lower()
  86. This way, you'll be able to pass, say, an integer to this filter, and it
  87. won't cause an ``AttributeError`` (because integers don't have ``lower()``
  88. methods).
  89. Registering custom filters
  90. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  91. Once you've written your filter definition, you need to register it with
  92. your ``Library`` instance, to make it available to Django's template language::
  93. register.filter('cut', cut)
  94. register.filter('lower', lower)
  95. The ``Library.filter()`` method takes two arguments:
  96. 1. The name of the filter -- a string.
  97. 2. The compilation function -- a Python function (not the name of the
  98. function as a string).
  99. You can use ``register.filter()`` as a decorator instead::
  100. @register.filter(name='cut')
  101. @stringfilter
  102. def cut(value, arg):
  103. return value.replace(arg, '')
  104. @register.filter
  105. @stringfilter
  106. def lower(value):
  107. return value.lower()
  108. If you leave off the ``name`` argument, as in the second example above, Django
  109. will use the function's name as the filter name.
  110. Filters and auto-escaping
  111. ~~~~~~~~~~~~~~~~~~~~~~~~~
  112. When writing a custom filter, give some thought to how the filter will interact
  113. with Django's auto-escaping behavior. Note that three types of strings can be
  114. passed around inside the template code:
  115. * **Raw strings** are the native Python ``str`` or ``unicode`` types. On
  116. output, they're escaped if auto-escaping is in effect and presented
  117. unchanged, otherwise.
  118. * **Safe strings** are strings that have been marked safe from further
  119. escaping at output time. Any necessary escaping has already been done.
  120. They're commonly used for output that contains raw HTML that is intended
  121. to be interpreted as-is on the client side.
  122. Internally, these strings are of type ``SafeString`` or ``SafeUnicode``.
  123. They share a common base class of ``SafeData``, so you can test
  124. for them using code like::
  125. if isinstance(value, SafeData):
  126. # Do something with the "safe" string.
  127. * **Strings marked as "needing escaping"** are *always* escaped on
  128. output, regardless of whether they are in an ``autoescape`` block or not.
  129. These strings are only escaped once, however, even if auto-escaping
  130. applies.
  131. Internally, these strings are of type ``EscapeString`` or
  132. ``EscapeUnicode``. Generally you don't have to worry about these; they
  133. exist for the implementation of the ``escape`` filter.
  134. Template filter code falls into one of two situations:
  135. 1. Your filter does not introduce any HTML-unsafe characters (``<``, ``>``,
  136. ``'``, ``"`` or ``&``) into the result that were not already present. In
  137. this case, you can let Django take care of all the auto-escaping
  138. handling for you. All you need to do is put the ``is_safe`` attribute on
  139. your filter function and set it to ``True``, like so::
  140. @register.filter
  141. def myfilter(value):
  142. return value
  143. myfilter.is_safe = True
  144. This attribute tells Django that if a "safe" string is passed into your
  145. filter, the result will still be "safe" and if a non-safe string is
  146. passed in, Django will automatically escape it, if necessary.
  147. You can think of this as meaning "this filter is safe -- it doesn't
  148. introduce any possibility of unsafe HTML."
  149. The reason ``is_safe`` is necessary is because there are plenty of
  150. normal string operations that will turn a ``SafeData`` object back into
  151. a normal ``str`` or ``unicode`` object and, rather than try to catch
  152. them all, which would be very difficult, Django repairs the damage after
  153. the filter has completed.
  154. For example, suppose you have a filter that adds the string ``xx`` to the
  155. end of any input. Since this introduces no dangerous HTML characters to
  156. the result (aside from any that were already present), you should mark
  157. your filter with ``is_safe``::
  158. @register.filter
  159. def add_xx(value):
  160. return '%sxx' % value
  161. add_xx.is_safe = True
  162. When this filter is used in a template where auto-escaping is enabled,
  163. Django will escape the output whenever the input is not already marked as
  164. "safe".
  165. By default, ``is_safe`` defaults to ``False``, and you can omit it from
  166. any filters where it isn't required.
  167. Be careful when deciding if your filter really does leave safe strings
  168. as safe. If you're *removing* characters, you might inadvertently leave
  169. unbalanced HTML tags or entities in the result. For example, removing a
  170. ``>`` from the input might turn ``<a>`` into ``<a``, which would need to
  171. be escaped on output to avoid causing problems. Similarly, removing a
  172. semicolon (``;``) can turn ``&amp;`` into ``&amp``, which is no longer a
  173. valid entity and thus needs further escaping. Most cases won't be nearly
  174. this tricky, but keep an eye out for any problems like that when
  175. reviewing your code.
  176. Marking a filter ``is_safe`` will coerce the filter's return value to
  177. a string. If your filter should return a boolean or other non-string
  178. value, marking it ``is_safe`` will probably have unintended
  179. consequences (such as converting a boolean False to the string
  180. 'False').
  181. 2. Alternatively, your filter code can manually take care of any necessary
  182. escaping. This is necessary when you're introducing new HTML markup into
  183. the result. You want to mark the output as safe from further
  184. escaping so that your HTML markup isn't escaped further, so you'll need
  185. to handle the input yourself.
  186. To mark the output as a safe string, use
  187. :func:`django.utils.safestring.mark_safe`.
  188. Be careful, though. You need to do more than just mark the output as
  189. safe. You need to ensure it really *is* safe, and what you do depends on
  190. whether auto-escaping is in effect. The idea is to write filters than
  191. can operate in templates where auto-escaping is either on or off in
  192. order to make things easier for your template authors.
  193. In order for your filter to know the current auto-escaping state, set
  194. the ``needs_autoescape`` attribute to ``True`` on your function. (If you
  195. don't specify this attribute, it defaults to ``False``). This attribute
  196. tells Django that your filter function wants to be passed an extra
  197. keyword argument, called ``autoescape``, that is ``True`` if
  198. auto-escaping is in effect and ``False`` otherwise.
  199. For example, let's write a filter that emphasizes the first character of
  200. a string::
  201. from django.utils.html import conditional_escape
  202. from django.utils.safestring import mark_safe
  203. def initial_letter_filter(text, autoescape=None):
  204. first, other = text[0], text[1:]
  205. if autoescape:
  206. esc = conditional_escape
  207. else:
  208. esc = lambda x: x
  209. result = '<strong>%s</strong>%s' % (esc(first), esc(other))
  210. return mark_safe(result)
  211. initial_letter_filter.needs_autoescape = True
  212. The ``needs_autoescape`` attribute on the filter function and the
  213. ``autoescape`` keyword argument mean that our function will know whether
  214. automatic escaping is in effect when the filter is called. We use
  215. ``autoescape`` to decide whether the input data needs to be passed
  216. through ``django.utils.html.conditional_escape`` or not. (In the latter
  217. case, we just use the identity function as the "escape" function.) The
  218. ``conditional_escape()`` function is like ``escape()`` except it only
  219. escapes input that is **not** a ``SafeData`` instance. If a ``SafeData``
  220. instance is passed to ``conditional_escape()``, the data is returned
  221. unchanged.
  222. Finally, in the above example, we remember to mark the result as safe
  223. so that our HTML is inserted directly into the template without further
  224. escaping.
  225. There's no need to worry about the ``is_safe`` attribute in this case
  226. (although including it wouldn't hurt anything). Whenever you manually
  227. handle the auto-escaping issues and return a safe string, the
  228. ``is_safe`` attribute won't change anything either way.
  229. Writing custom template tags
  230. ----------------------------
  231. Tags are more complex than filters, because tags can do anything.
  232. A quick overview
  233. ~~~~~~~~~~~~~~~~
  234. Above, this document explained that the template system works in a two-step
  235. process: compiling and rendering. To define a custom template tag, you specify
  236. how the compilation works and how the rendering works.
  237. When Django compiles a template, it splits the raw template text into
  238. ''nodes''. Each node is an instance of ``django.template.Node`` and has
  239. a ``render()`` method. A compiled template is, simply, a list of ``Node``
  240. objects. When you call ``render()`` on a compiled template object, the template
  241. calls ``render()`` on each ``Node`` in its node list, with the given context.
  242. The results are all concatenated together to form the output of the template.
  243. Thus, to define a custom template tag, you specify how the raw template tag is
  244. converted into a ``Node`` (the compilation function), and what the node's
  245. ``render()`` method does.
  246. Writing the compilation function
  247. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  248. For each template tag the template parser encounters, it calls a Python
  249. function with the tag contents and the parser object itself. This function is
  250. responsible for returning a ``Node`` instance based on the contents of the tag.
  251. For example, let's write a template tag, ``{% current_time %}``, that displays
  252. the current date/time, formatted according to a parameter given in the tag, in
  253. `strftime syntax`_. It's a good idea to decide the tag syntax before anything
  254. else. In our case, let's say the tag should be used like this:
  255. .. code-block:: html+django
  256. <p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>
  257. .. _`strftime syntax`: http://docs.python.org/library/time.html#time.strftime
  258. The parser for this function should grab the parameter and create a ``Node``
  259. object::
  260. from django import template
  261. def do_current_time(parser, token):
  262. try:
  263. # split_contents() knows not to split quoted strings.
  264. tag_name, format_string = token.split_contents()
  265. except ValueError:
  266. raise template.TemplateSyntaxError("%r tag requires a single argument" % token.contents.split()[0])
  267. if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
  268. raise template.TemplateSyntaxError("%r tag's argument should be in quotes" % tag_name)
  269. return CurrentTimeNode(format_string[1:-1])
  270. Notes:
  271. * ``parser`` is the template parser object. We don't need it in this
  272. example.
  273. * ``token.contents`` is a string of the raw contents of the tag. In our
  274. example, it's ``'current_time "%Y-%m-%d %I:%M %p"'``.
  275. * The ``token.split_contents()`` method separates the arguments on spaces
  276. while keeping quoted strings together. The more straightforward
  277. ``token.contents.split()`` wouldn't be as robust, as it would naively
  278. split on *all* spaces, including those within quoted strings. It's a good
  279. idea to always use ``token.split_contents()``.
  280. * This function is responsible for raising
  281. ``django.template.TemplateSyntaxError``, with helpful messages, for
  282. any syntax error.
  283. * The ``TemplateSyntaxError`` exceptions use the ``tag_name`` variable.
  284. Don't hard-code the tag's name in your error messages, because that
  285. couples the tag's name to your function. ``token.contents.split()[0]``
  286. will ''always'' be the name of your tag -- even when the tag has no
  287. arguments.
  288. * The function returns a ``CurrentTimeNode`` with everything the node needs
  289. to know about this tag. In this case, it just passes the argument --
  290. ``"%Y-%m-%d %I:%M %p"``. The leading and trailing quotes from the
  291. template tag are removed in ``format_string[1:-1]``.
  292. * The parsing is very low-level. The Django developers have experimented
  293. with writing small frameworks on top of this parsing system, using
  294. techniques such as EBNF grammars, but those experiments made the template
  295. engine too slow. It's low-level because that's fastest.
  296. Writing the renderer
  297. ~~~~~~~~~~~~~~~~~~~~
  298. The second step in writing custom tags is to define a ``Node`` subclass that
  299. has a ``render()`` method.
  300. Continuing the above example, we need to define ``CurrentTimeNode``::
  301. from django import template
  302. import datetime
  303. class CurrentTimeNode(template.Node):
  304. def __init__(self, format_string):
  305. self.format_string = format_string
  306. def render(self, context):
  307. return datetime.datetime.now().strftime(self.format_string)
  308. Notes:
  309. * ``__init__()`` gets the ``format_string`` from ``do_current_time()``.
  310. Always pass any options/parameters/arguments to a ``Node`` via its
  311. ``__init__()``.
  312. * The ``render()`` method is where the work actually happens.
  313. * ``render()`` should never raise ``TemplateSyntaxError`` or any other
  314. exception. It should fail silently, just as template filters should.
  315. Ultimately, this decoupling of compilation and rendering results in an
  316. efficient template system, because a template can render multiple contexts
  317. without having to be parsed multiple times.
  318. Auto-escaping considerations
  319. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  320. The output from template tags is **not** automatically run through the
  321. auto-escaping filters. However, there are still a couple of things you should
  322. keep in mind when writing a template tag.
  323. If the ``render()`` function of your template stores the result in a context
  324. variable (rather than returning the result in a string), it should take care
  325. to call ``mark_safe()`` if appropriate. When the variable is ultimately
  326. rendered, it will be affected by the auto-escape setting in effect at the
  327. time, so content that should be safe from further escaping needs to be marked
  328. as such.
  329. Also, if your template tag creates a new context for performing some
  330. sub-rendering, set the auto-escape attribute to the current context's value.
  331. The ``__init__`` method for the ``Context`` class takes a parameter called
  332. ``autoescape`` that you can use for this purpose. For example::
  333. def render(self, context):
  334. # ...
  335. new_context = Context({'var': obj}, autoescape=context.autoescape)
  336. # ... Do something with new_context ...
  337. This is not a very common situation, but it's useful if you're rendering a
  338. template yourself. For example::
  339. def render(self, context):
  340. t = template.loader.get_template('small_fragment.html')
  341. return t.render(Context({'var': obj}, autoescape=context.autoescape))
  342. If we had neglected to pass in the current ``context.autoescape`` value to our
  343. new ``Context`` in this example, the results would have *always* been
  344. automatically escaped, which may not be the desired behavior if the template
  345. tag is used inside a ``{% autoescape off %}`` block.
  346. .. _template_tag_thread_safety:
  347. Thread-safety considerations
  348. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  349. .. versionadded:: 1.2
  350. Once a node is parsed, its ``render`` method may be called any number of times.
  351. Since Django is sometimes run in multi-threaded environments, a single node may
  352. be simultaneously rendering with different contexts in response to two separate
  353. requests. Therefore, it's important to make sure your template tags are thread
  354. safe.
  355. To make sure your template tags are thread safe, you should never store state
  356. information on the node itself. For example, Django provides a builtin ``cycle``
  357. template tag that cycles among a list of given strings each time it's rendered::
  358. {% for o in some_list %}
  359. <tr class="{% cycle 'row1' 'row2' %}>
  360. ...
  361. </tr>
  362. {% endfor %}
  363. A naive implementation of ``CycleNode`` might look something like this::
  364. class CycleNode(Node):
  365. def __init__(self, cyclevars):
  366. self.cycle_iter = itertools.cycle(cyclevars)
  367. def render(self, context):
  368. return self.cycle_iter.next()
  369. But, suppose we have two templates rendering the template snippet from above at
  370. the same time:
  371. 1. Thread 1 performs its first loop iteration, ``CycleNode.render()``
  372. returns 'row1'
  373. 2. Thread 2 performs its first loop iteration, ``CycleNode.render()``
  374. returns 'row2'
  375. 3. Thread 1 performs its second loop iteration, ``CycleNode.render()``
  376. returns 'row1'
  377. 4. Thread 2 performs its second loop iteration, ``CycleNode.render()``
  378. returns 'row2'
  379. The CycleNode is iterating, but it's iterating globally. As far as Thread 1
  380. and Thread 2 are concerned, it's always returning the same value. This is
  381. obviously not what we want!
  382. To address this problem, Django provides a ``render_context`` that's associated
  383. with the ``context`` of the template that is currently being rendered. The
  384. ``render_context`` behaves like a Python dictionary, and should be used to store
  385. ``Node`` state between invocations of the ``render`` method.
  386. Let's refactor our ``CycleNode`` implementation to use the ``render_context``::
  387. class CycleNode(Node):
  388. def __init__(self, cyclevars):
  389. self.cyclevars = cyclevars
  390. def render(self, context):
  391. if self not in context.render_context:
  392. context.render_context[self] = itertools.cycle(self.cyclevars)
  393. cycle_iter = context.render_context[self]
  394. return cycle_iter.next()
  395. Note that it's perfectly safe to store global information that will not change
  396. throughout the life of the ``Node`` as an attribute. In the case of
  397. ``CycleNode``, the ``cyclevars`` argument doesn't change after the ``Node`` is
  398. instantiated, so we don't need to put it in the ``render_context``. But state
  399. information that is specific to the template that is currently being rendered,
  400. like the current iteration of the ``CycleNode``, should be stored in the
  401. ``render_context``.
  402. .. note::
  403. Notice how we used ``self`` to scope the ``CycleNode`` specific information
  404. within the ``render_context``. There may be multiple ``CycleNodes`` in a
  405. given template, so we need to be careful not to clobber another node's state
  406. information. The easiest way to do this is to always use ``self`` as the key
  407. into ``render_context``. If you're keeping track of several state variables,
  408. make ``render_context[self]`` a dictionary.
  409. Registering the tag
  410. ~~~~~~~~~~~~~~~~~~~
  411. Finally, register the tag with your module's ``Library`` instance, as explained
  412. in "Writing custom template filters" above. Example::
  413. register.tag('current_time', do_current_time)
  414. The ``tag()`` method takes two arguments:
  415. 1. The name of the template tag -- a string. If this is left out, the
  416. name of the compilation function will be used.
  417. 2. The compilation function -- a Python function (not the name of the
  418. function as a string).
  419. As with filter registration, it is also possible to use this as a decorator::
  420. @register.tag(name="current_time")
  421. def do_current_time(parser, token):
  422. # ...
  423. @register.tag
  424. def shout(parser, token):
  425. # ...
  426. If you leave off the ``name`` argument, as in the second example above, Django
  427. will use the function's name as the tag name.
  428. Passing template variables to the tag
  429. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  430. Although you can pass any number of arguments to a template tag using
  431. ``token.split_contents()``, the arguments are all unpacked as
  432. string literals. A little more work is required in order to pass dynamic
  433. content (a template variable) to a template tag as an argument.
  434. While the previous examples have formatted the current time into a string and
  435. returned the string, suppose you wanted to pass in a ``DateTimeField`` from an
  436. object and have the template tag format that date-time:
  437. .. code-block:: html+django
  438. <p>This post was last updated at {% format_time blog_entry.date_updated "%Y-%m-%d %I:%M %p" %}.</p>
  439. Initially, ``token.split_contents()`` will return three values:
  440. 1. The tag name ``format_time``.
  441. 2. The string "blog_entry.date_updated" (without the surrounding quotes).
  442. 3. The formatting string "%Y-%m-%d %I:%M %p". The return value from
  443. ``split_contents()`` will include the leading and trailing quotes for
  444. string literals like this.
  445. Now your tag should begin to look like this::
  446. from django import template
  447. def do_format_time(parser, token):
  448. try:
  449. # split_contents() knows not to split quoted strings.
  450. tag_name, date_to_be_formatted, format_string = token.split_contents()
  451. except ValueError:
  452. raise template.TemplateSyntaxError("%r tag requires exactly two arguments" % token.contents.split()[0])
  453. if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
  454. raise template.TemplateSyntaxError("%r tag's argument should be in quotes" % tag_name)
  455. return FormatTimeNode(date_to_be_formatted, format_string[1:-1])
  456. You also have to change the renderer to retrieve the actual contents of the
  457. ``date_updated`` property of the ``blog_entry`` object. This can be
  458. accomplished by using the ``Variable()`` class in ``django.template``.
  459. To use the ``Variable`` class, simply instantiate it with the name of the
  460. variable to be resolved, and then call ``variable.resolve(context)``. So,
  461. for example::
  462. class FormatTimeNode(template.Node):
  463. def __init__(self, date_to_be_formatted, format_string):
  464. self.date_to_be_formatted = template.Variable(date_to_be_formatted)
  465. self.format_string = format_string
  466. def render(self, context):
  467. try:
  468. actual_date = self.date_to_be_formatted.resolve(context)
  469. return actual_date.strftime(self.format_string)
  470. except template.VariableDoesNotExist:
  471. return ''
  472. Variable resolution will throw a ``VariableDoesNotExist`` exception if it cannot
  473. resolve the string passed to it in the current context of the page.
  474. Shortcut for simple tags
  475. ~~~~~~~~~~~~~~~~~~~~~~~~
  476. Many template tags take a number of arguments -- strings or template variables
  477. -- and return a string after doing some processing based solely on
  478. the input arguments and some external information. For example, the
  479. ``current_time`` tag we wrote above is of this variety: we give it a format
  480. string, it returns the time as a string.
  481. To ease the creation of these types of tags, Django provides a helper function,
  482. ``simple_tag``. This function, which is a method of
  483. ``django.template.Library``, takes a function that accepts any number of
  484. arguments, wraps it in a ``render`` function and the other necessary bits
  485. mentioned above and registers it with the template system.
  486. Our earlier ``current_time`` function could thus be written like this::
  487. def current_time(format_string):
  488. return datetime.datetime.now().strftime(format_string)
  489. register.simple_tag(current_time)
  490. The decorator syntax also works::
  491. @register.simple_tag
  492. def current_time(format_string):
  493. ...
  494. A couple of things to note about the ``simple_tag`` helper function:
  495. * Checking for the required number of arguments, etc., has already been
  496. done by the time our function is called, so we don't need to do that.
  497. * The quotes around the argument (if any) have already been stripped away,
  498. so we just receive a plain string.
  499. * If the argument was a template variable, our function is passed the
  500. current value of the variable, not the variable itself.
  501. .. versionadded:: 1.3
  502. If your template tag needs to access the current context, you can use the
  503. ``takes_context`` argument when registering your tag::
  504. # The first argument *must* be called "context" here.
  505. def current_time(context, format_string):
  506. timezone = context['timezone']
  507. return your_get_current_time_method(timezone, format_string)
  508. register.simple_tag(takes_context=True)(current_time)
  509. Or, using decorator syntax::
  510. @register.simple_tag(takes_context=True)
  511. def current_time(context, format_string):
  512. timezone = context['timezone']
  513. return your_get_current_time_method(timezone, format_string)
  514. For more information on how the ``takes_context`` option works, see the section
  515. on `inclusion tags`_.
  516. .. _howto-custom-template-tags-inclusion-tags:
  517. Inclusion tags
  518. ~~~~~~~~~~~~~~
  519. Another common type of template tag is the type that displays some data by
  520. rendering *another* template. For example, Django's admin interface uses custom
  521. template tags to display the buttons along the bottom of the "add/change" form
  522. pages. Those buttons always look the same, but the link targets change depending
  523. on the object being edited -- so they're a perfect case for using a small
  524. template that is filled with details from the current object. (In the admin's
  525. case, this is the ``submit_row`` tag.)
  526. These sorts of tags are called "inclusion tags".
  527. Writing inclusion tags is probably best demonstrated by example. Let's write a
  528. tag that outputs a list of choices for a given ``Poll`` object, such as was
  529. created in the :ref:`tutorials <creating-models>`. We'll use the tag like this:
  530. .. code-block:: html+django
  531. {% show_results poll %}
  532. ...and the output will be something like this:
  533. .. code-block:: html
  534. <ul>
  535. <li>First choice</li>
  536. <li>Second choice</li>
  537. <li>Third choice</li>
  538. </ul>
  539. First, define the function that takes the argument and produces a dictionary of
  540. data for the result. The important point here is we only need to return a
  541. dictionary, not anything more complex. This will be used as a template context
  542. for the template fragment. Example::
  543. def show_results(poll):
  544. choices = poll.choice_set.all()
  545. return {'choices': choices}
  546. Next, create the template used to render the tag's output. This template is a
  547. fixed feature of the tag: the tag writer specifies it, not the template
  548. designer. Following our example, the template is very simple:
  549. .. code-block:: html+django
  550. <ul>
  551. {% for choice in choices %}
  552. <li> {{ choice }} </li>
  553. {% endfor %}
  554. </ul>
  555. Now, create and register the inclusion tag by calling the ``inclusion_tag()``
  556. method on a ``Library`` object. Following our example, if the above template is
  557. in a file called ``results.html`` in a directory that's searched by the template
  558. loader, we'd register the tag like this::
  559. # Here, register is a django.template.Library instance, as before
  560. register.inclusion_tag('results.html')(show_results)
  561. As always, decorator syntax works as well, so we could have written::
  562. @register.inclusion_tag('results.html')
  563. def show_results(poll):
  564. ...
  565. ...when first creating the function.
  566. Sometimes, your inclusion tags might require a large number of arguments,
  567. making it a pain for template authors to pass in all the arguments and remember
  568. their order. To solve this, Django provides a ``takes_context`` option for
  569. inclusion tags. If you specify ``takes_context`` in creating a template tag,
  570. the tag will have no required arguments, and the underlying Python function
  571. will have one argument -- the template context as of when the tag was called.
  572. For example, say you're writing an inclusion tag that will always be used in a
  573. context that contains ``home_link`` and ``home_title`` variables that point
  574. back to the main page. Here's what the Python function would look like::
  575. # The first argument *must* be called "context" here.
  576. def jump_link(context):
  577. return {
  578. 'link': context['home_link'],
  579. 'title': context['home_title'],
  580. }
  581. # Register the custom tag as an inclusion tag with takes_context=True.
  582. register.inclusion_tag('link.html', takes_context=True)(jump_link)
  583. (Note that the first parameter to the function *must* be called ``context``.)
  584. In that ``register.inclusion_tag()`` line, we specified ``takes_context=True``
  585. and the name of the template. Here's what the template ``link.html`` might look
  586. like:
  587. .. code-block:: html+django
  588. Jump directly to <a href="{{ link }}">{{ title }}</a>.
  589. Then, any time you want to use that custom tag, load its library and call it
  590. without any arguments, like so:
  591. .. code-block:: html+django
  592. {% jump_link %}
  593. Note that when you're using ``takes_context=True``, there's no need to pass
  594. arguments to the template tag. It automatically gets access to the context.
  595. The ``takes_context`` parameter defaults to ``False``. When it's set to *True*,
  596. the tag is passed the context object, as in this example. That's the only
  597. difference between this case and the previous ``inclusion_tag`` example.
  598. Setting a variable in the context
  599. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  600. The above examples simply output a value. Generally, it's more flexible if your
  601. template tags set template variables instead of outputting values. That way,
  602. template authors can reuse the values that your template tags create.
  603. To set a variable in the context, just use dictionary assignment on the context
  604. object in the ``render()`` method. Here's an updated version of
  605. ``CurrentTimeNode`` that sets a template variable ``current_time`` instead of
  606. outputting it::
  607. class CurrentTimeNode2(template.Node):
  608. def __init__(self, format_string):
  609. self.format_string = format_string
  610. def render(self, context):
  611. context['current_time'] = datetime.datetime.now().strftime(self.format_string)
  612. return ''
  613. Note that ``render()`` returns the empty string. ``render()`` should always
  614. return string output. If all the template tag does is set a variable,
  615. ``render()`` should return the empty string.
  616. Here's how you'd use this new version of the tag:
  617. .. code-block:: html+django
  618. {% current_time "%Y-%M-%d %I:%M %p" %}<p>The time is {{ current_time }}.</p>
  619. .. admonition:: Variable scope in context
  620. Any variable set in the context will only be available in the same ``block``
  621. of the template in which it was assigned. This behavior is intentional;
  622. it provides a scope for variables so that they don't conflict with
  623. context in other blocks.
  624. But, there's a problem with ``CurrentTimeNode2``: The variable name
  625. ``current_time`` is hard-coded. This means you'll need to make sure your
  626. template doesn't use ``{{ current_time }}`` anywhere else, because the
  627. ``{% current_time %}`` will blindly overwrite that variable's value. A cleaner
  628. solution is to make the template tag specify the name of the output variable,
  629. like so:
  630. .. code-block:: html+django
  631. {% current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
  632. <p>The current time is {{ my_current_time }}.</p>
  633. To do that, you'll need to refactor both the compilation function and ``Node``
  634. class, like so::
  635. class CurrentTimeNode3(template.Node):
  636. def __init__(self, format_string, var_name):
  637. self.format_string = format_string
  638. self.var_name = var_name
  639. def render(self, context):
  640. context[self.var_name] = datetime.datetime.now().strftime(self.format_string)
  641. return ''
  642. import re
  643. def do_current_time(parser, token):
  644. # This version uses a regular expression to parse tag contents.
  645. try:
  646. # Splitting by None == splitting by spaces.
  647. tag_name, arg = token.contents.split(None, 1)
  648. except ValueError:
  649. raise template.TemplateSyntaxError("%r tag requires arguments" % token.contents.split()[0])
  650. m = re.search(r'(.*?) as (\w+)', arg)
  651. if not m:
  652. raise template.TemplateSyntaxError("%r tag had invalid arguments" % tag_name)
  653. format_string, var_name = m.groups()
  654. if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
  655. raise template.TemplateSyntaxError("%r tag's argument should be in quotes" % tag_name)
  656. return CurrentTimeNode3(format_string[1:-1], var_name)
  657. The difference here is that ``do_current_time()`` grabs the format string and
  658. the variable name, passing both to ``CurrentTimeNode3``.
  659. Parsing until another block tag
  660. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  661. Template tags can work in tandem. For instance, the standard ``{% comment %}``
  662. tag hides everything until ``{% endcomment %}``. To create a template tag such
  663. as this, use ``parser.parse()`` in your compilation function.
  664. Here's how the standard ``{% comment %}`` tag is implemented::
  665. def do_comment(parser, token):
  666. nodelist = parser.parse(('endcomment',))
  667. parser.delete_first_token()
  668. return CommentNode()
  669. class CommentNode(template.Node):
  670. def render(self, context):
  671. return ''
  672. ``parser.parse()`` takes a tuple of names of block tags ''to parse until''. It
  673. returns an instance of ``django.template.NodeList``, which is a list of
  674. all ``Node`` objects that the parser encountered ''before'' it encountered
  675. any of the tags named in the tuple.
  676. In ``"nodelist = parser.parse(('endcomment',))"`` in the above example,
  677. ``nodelist`` is a list of all nodes between the ``{% comment %}`` and
  678. ``{% endcomment %}``, not counting ``{% comment %}`` and ``{% endcomment %}``
  679. themselves.
  680. After ``parser.parse()`` is called, the parser hasn't yet "consumed" the
  681. ``{% endcomment %}`` tag, so the code needs to explicitly call
  682. ``parser.delete_first_token()``.
  683. ``CommentNode.render()`` simply returns an empty string. Anything between
  684. ``{% comment %}`` and ``{% endcomment %}`` is ignored.
  685. Parsing until another block tag, and saving contents
  686. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  687. In the previous example, ``do_comment()`` discarded everything between
  688. ``{% comment %}`` and ``{% endcomment %}``. Instead of doing that, it's
  689. possible to do something with the code between block tags.
  690. For example, here's a custom template tag, ``{% upper %}``, that capitalizes
  691. everything between itself and ``{% endupper %}``.
  692. Usage:
  693. .. code-block:: html+django
  694. {% upper %}This will appear in uppercase, {{ your_name }}.{% endupper %}
  695. As in the previous example, we'll use ``parser.parse()``. But this time, we
  696. pass the resulting ``nodelist`` to the ``Node``::
  697. def do_upper(parser, token):
  698. nodelist = parser.parse(('endupper',))
  699. parser.delete_first_token()
  700. return UpperNode(nodelist)
  701. class UpperNode(template.Node):
  702. def __init__(self, nodelist):
  703. self.nodelist = nodelist
  704. def render(self, context):
  705. output = self.nodelist.render(context)
  706. return output.upper()
  707. The only new concept here is the ``self.nodelist.render(context)`` in
  708. ``UpperNode.render()``.
  709. For more examples of complex rendering, see the source code for ``{% if %}``,
  710. ``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
  711. ``django/template/defaulttags.py``.