| | 746 | Shortcut for simple tags |
|---|
| | 747 | ~~~~~~~~~~~~~~~~~~~~~~~~ |
|---|
| | 748 | |
|---|
| | 749 | Many template tags take a single argument -- a string or a template variable |
|---|
| | 750 | reference -- and return a string after doing some processing based solely on |
|---|
| | 751 | the 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 |
|---|
| | 753 | string, it returns the time as a string. |
|---|
| | 754 | |
|---|
| | 755 | To 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 |
|---|
| | 758 | it in a ``render`` function and the other necessary bits mentioned above and |
|---|
| | 759 | registers it with the template system. |
|---|
| | 760 | |
|---|
| | 761 | Our 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 | |
|---|
| | 778 | In Python 2.4, the decorator syntax also works:: |
|---|
| | 779 | |
|---|
| | 780 | @simple_tag |
|---|
| | 781 | def do_current_time(token): |
|---|
| | 782 | ... |
|---|
| | 783 | |
|---|
| | 784 | Inclusion tags |
|---|
| | 785 | ~~~~~~~~~~~~~~ |
|---|
| | 786 | |
|---|
| | 787 | Another type of template tag that is sometimes useful is when you want to |
|---|
| | 788 | display some data that is computed at render time in a template fragment. For |
|---|
| | 789 | example, in Django's admin interface, there is a line of buttons along the |
|---|
| | 790 | bottom of the `create/edit record` screen. These buttons always look the same, |
|---|
| | 791 | but the link targets change depending upon the object being edited. So they |
|---|
| | 792 | are a perfect example for using a small template that is filled in with |
|---|
| | 793 | details from the current object. To save typing, it would also be nice if we |
|---|
| | 794 | could wrap this whole display up in a single tag (in the admin templates this |
|---|
| | 795 | is the ``submit_row`` tag). |
|---|
| | 796 | |
|---|
| | 797 | We call these sorts of tags `inclusion tags`. In your template, you pass in |
|---|
| | 798 | any appropriate arguments and the tag uses those arguments, together with the |
|---|
| | 799 | current context to render a template and include the result in the output. |
|---|
| | 800 | |
|---|
| | 801 | Writing inclusion tags is probably best demonstrated by example. We will write |
|---|
| | 802 | a tag that outputs a list of choices for a Poll object, such as was created in |
|---|
| | 803 | the tutorials_. We will use this tag like this:: |
|---|
| | 804 | |
|---|
| | 805 | {{ show_results poll }} |
|---|
| | 806 | |
|---|
| | 807 | and 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 | |
|---|
| | 815 | First, we define the function which takes the argument and produces a |
|---|
| | 816 | dictionary of data for the result. The important point here is we only need to |
|---|
| | 817 | return a dictionary, not anything more complex. This will be used to substitue |
|---|
| | 818 | for values in the template fragment, just as when templates are used |
|---|
| | 819 | elsewhere. |
|---|
| | 820 | |
|---|
| | 821 | :: |
|---|
| | 822 | |
|---|
| | 823 | def show_results(poll): |
|---|
| | 824 | choices = poll.choice_set.all() |
|---|
| | 825 | return {'choices': choices} |
|---|
| | 826 | |
|---|
| | 827 | We also need to create the template that is used to render the output. This |
|---|
| | 828 | template is a fixed feature of the tag: the tag writer specifies it, not the |
|---|
| | 829 | template 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 | |
|---|
| | 837 | Now we can create the inclusion tag. Suppose the above template is in a file |
|---|
| | 838 | called ``results.html`` in a directory that is searched by the template |
|---|
| | 839 | loader. 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 | |
|---|
| | 846 | As always, Python 2.4 decorator syntax works as well, so we could have |
|---|
| | 847 | written |
|---|
| | 848 | |
|---|
| | 849 | :: |
|---|
| | 850 | |
|---|
| | 851 | @inclusion_tag('results.html') |
|---|
| | 852 | def show_results(poll): |
|---|
| | 853 | ... |
|---|
| | 854 | |
|---|
| | 855 | when first creating the function. |
|---|
| | 856 | |
|---|
| | 857 | In some cases, an inclusion tag might require a large number of arguments to |
|---|
| | 858 | display itself properly. In essence, it would depend largely on the current |
|---|
| | 859 | context it was being rendered with. We can make these sorts of tags easier to |
|---|
| | 860 | write by telling the ``inclusion_tag`` function that the whole context |
|---|
| | 861 | should be passed in as an argument to the function. This will be done |
|---|
| | 862 | invisibly as far as the template tag user is concerned: they will not need to |
|---|
| | 863 | do anything to pass in the context. |
|---|
| | 864 | |
|---|
| | 865 | For example, suppose we are writing an inclusion tag that will always be used |
|---|
| | 866 | in a context that contains ``home_link`` and ``home_title`` variables that |
|---|
| | 867 | point back to the main page. We can write a tag that is used like this:: |
|---|
| | 868 | |
|---|
| | 869 | {{ jump_link }} |
|---|
| | 870 | |
|---|
| | 871 | and renders this:: |
|---|
| | 872 | |
|---|
| | 873 | Jump directly to <a href="http://example.com/home">Home</a> |
|---|
| | 874 | |
|---|
| | 875 | The tag function is almost as simple as before. This time it takes no |
|---|
| | 876 | arguments except the ``context`` (and the parameter `must` be called |
|---|
| | 877 | ``context`` in this case; the special parameter named is used internally by |
|---|
| | 878 | Django 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 | |
|---|
| | 889 | Our template is very simple again:: |
|---|
| | 890 | |
|---|
| | 891 | Jump directly to <a href="{{ link }}">{{ title }}</a>. |
|---|
| | 892 | |
|---|
| | 893 | Assuming the template is in a file called ``link.html``, we register this new |
|---|
| | 894 | tag as follows:: |
|---|
| | 895 | |
|---|
| | 896 | register.inclusion_tag('link.html', takes_context = True)(jump_link) |
|---|
| | 897 | |
|---|
| | 898 | The ``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 |
|---|
| | 900 | only difference between this case and our previous use of ``inclusion_tag``. |
|---|
| | 901 | |
|---|
| | 902 | .. _tutorials: http://www.djangoproject.com/documentation/tutorial1/#creating-models |
|---|
| | 903 | |
|---|