Django

Code

Changeset 2941

Show
Ignore:
Timestamp:
05/18/06 21:02:34 (3 years ago)
Author:
mtredinnick
Message:

Documented the simple_tag and inclusion_tag functions that make writing certain
types of template tags easier.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/docs/templates_python.txt

    r2927 r2941  
    744744will use the function's name as the tag name. 
    745745 
     746Shortcut for simple tags 
     747~~~~~~~~~~~~~~~~~~~~~~~~ 
     748 
     749Many template tags take a single argument -- a string or a template variable 
     750reference -- and return a string after doing some processing based solely on 
     751the input argument and some external information. For example, the 
     752``current_time`` tag we wrote above is of this variety: we give it a format 
     753string, it returns the time as a string. 
     754 
     755To ease the creation of the types of tags, Django provides a helper function, 
     756``simple_tag``. This function, which is a method of 
     757``django.template.Library``, takes a function that accepts one argument, wraps 
     758it in a ``render`` function and the other necessary bits mentioned above and 
     759registers it with the template system. 
     760 
     761Our earlier ``current_time`` function could thus be written like this:: 
     762 
     763    # This version of do_current_time takes only a single argument and returns 
     764    # a string. 
     765 
     766    def do_current_time(token): 
     767        try: 
     768            # Splitting by None == splitting by spaces. 
     769            tag_name, format_string = token.contents.split(None, 1) 
     770        except ValueError: 
     771            raise template.TemplateSyntaxError, "%r tag requires an argument" % token.contents[0] 
     772        if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")): 
     773            raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name 
     774        return datetime.datetime.now().strftime(self.format_string[1:-1]) 
     775 
     776    register.simple_tag(do_current_time) 
     777 
     778In Python 2.4, the decorator syntax also works:: 
     779 
     780    @simple_tag 
     781    def do_current_time(token): 
     782        ... 
     783 
     784Inclusion tags 
     785~~~~~~~~~~~~~~ 
     786 
     787Another type of template tag that is sometimes useful is when you want to 
     788display some data that is computed at render time in a template fragment. For 
     789example, in Django's admin interface, there is a line of buttons along the 
     790bottom of the `create/edit record` screen. These buttons always look the same, 
     791but the link targets change depending upon the object being edited. So they 
     792are a perfect example for using a small template that is filled in with 
     793details from the current object. To save typing, it would also be nice if we 
     794could wrap this whole display up in a single tag (in the admin templates this 
     795is the ``submit_row`` tag). 
     796 
     797We call these sorts of tags `inclusion tags`. In your template, you pass in 
     798any appropriate arguments and the tag uses those arguments, together with the 
     799current context to render a template and include the result in the output. 
     800 
     801Writing inclusion tags is probably best demonstrated by example. We will write 
     802a tag that outputs a list of choices for a Poll object, such as was created in 
     803the tutorials_. We will use this tag like this:: 
     804 
     805    {{ show_results poll }} 
     806 
     807and the output will be something like this:: 
     808 
     809    <ul> 
     810      <li>First choice</li> 
     811      <li>Second choice</li> 
     812      <li>Third choice</li> 
     813    </ul> 
     814 
     815First, we define the function which takes the argument and produces a 
     816dictionary of data for the result. The important point here is we only need to 
     817return a dictionary, not anything more complex. This will be used to substitue 
     818for values in the template fragment, just as when templates are used 
     819elsewhere. 
     820 
     821:: 
     822 
     823    def show_results(poll): 
     824        choices = poll.choice_set.all() 
     825        return {'choices': choices} 
     826 
     827We also need to create the template that is used to render the output. This 
     828template is a fixed feature of the tag: the tag writer specifies it, not the 
     829template designer. In our case, the template is very simple:: 
     830 
     831    <ul> 
     832    {% for choice in choices %} 
     833        <li> {{ choice }} </li> 
     834    {% endfor %} 
     835    </ul> 
     836 
     837Now we can create the inclusion tag. Suppose the above template is in a file 
     838called ``results.html`` in a directory that is searched by the template 
     839loader. We register our new tag similarly to a normal tag. 
     840 
     841:: 
     842 
     843    # Here, register is a django.template.Library instance, as before 
     844    register.inclusion_tag('results.html')(show_results) 
     845 
     846As always, Python 2.4 decorator syntax works as well, so we could have 
     847written 
     848 
     849:: 
     850 
     851    @inclusion_tag('results.html') 
     852    def show_results(poll): 
     853        ... 
     854 
     855when first creating the function. 
     856 
     857In some cases, an inclusion tag might require a large number of arguments to 
     858display itself properly. In essence, it would depend largely on the current 
     859context it was being rendered with. We can make these sorts of tags easier to 
     860write by telling the ``inclusion_tag`` function that the whole context 
     861should be passed in as an argument to the function. This will be done 
     862invisibly as far as the template tag user is concerned: they will not need to 
     863do anything to pass in the context. 
     864 
     865For example, suppose we are writing an inclusion tag that will always be used 
     866in a context that contains ``home_link`` and ``home_title`` variables that 
     867point back to the main page. We can write a tag that is used like this:: 
     868 
     869    {{ jump_link }} 
     870 
     871and renders this:: 
     872 
     873    Jump directly to <a href="http://example.com/home">Home</a> 
     874 
     875The tag function is almost as simple as before. This time it takes no 
     876arguments except the ``context`` (and the parameter `must` be called 
     877``context`` in this case; the special parameter named is used internally by 
     878Django to fill in the values correctly). 
     879 
     880:: 
     881 
     882    # The first argument *must* be called "context" here. 
     883    def jump_link(context): 
     884        return { 
     885            'link': context['home_link'], 
     886            'title': context['home_title'], 
     887        } 
     888 
     889Our template is very simple again:: 
     890 
     891    Jump directly to <a href="{{ link }}">{{ title }}</a>. 
     892 
     893Assuming the template is in a file called ``link.html``, we register this new 
     894tag as follows:: 
     895 
     896    register.inclusion_tag('link.html', takes_context = True)(jump_link) 
     897 
     898The ``takes_context`` parameter here defaults to *False*. When it is set to 
     899*True*, our tag is passed the implicit context as in this example. That is the 
     900only difference between this case and our previous use of ``inclusion_tag``. 
     901 
     902.. _tutorials: http://www.djangoproject.com/documentation/tutorial1/#creating-models 
     903 
    746904Setting a variable in the context 
    747905~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~