How to Write Django Template Tags
Template tags can be useful for making your applications more reusable by other projects. For this example I will be adding to the
books project that I started in a previous post. Also, I’ve bundled the
example files into a google code project.
Start off by creating a folder called templatetags in your app directory and create two files in it. The first one named __init__.py and the second book_tags.py. There’s 3 things that we need to accomplish with our template tags. The first is to create a tag that will output the url for the action of the form. For example, {% get_book_form_url foo_object %}Next we need to get the form and assign it to a template variable that can be specified by the template variable. For example, {% book_form as bar_var %}. And the third template tag will get the books for an object and place in a template variable. For example, {% books_for_object foo_object as bar_var %}.
from django.template import Library, Node, TemplateSyntaxError from django.template import Variable, resolve_variable from django.utils.translation import ugettext as _ from django.contrib.contenttypes.models import ContentType from django.core.urlresolvers import reverse from books.models import Book register = Library() def get_contenttype_kwargs(content_object): """ Gets the basic kwargs necessary for form submission url """ kwargs = {'content_type_id': ContentType.objects.get_for_model(content_object).id, 'object_id': getattr(content_object, 'pk', getattr(content_object, 'id')), } return kwargs def get_book_form_url(content_object): """ prints url for form action """ kwargs = get_contenttype_kwargs(content_object) return reverse('new_book', kwargs=kwargs) class BooksForObjectsNode(Node): """ Get the books and add to the context """ def __init__(self, obj, context_var): self.obj = Variable(obj) self.context_var = context_var def render(self, context): content_type = ContentType.objects.get_for_model( self.obj.resolve(context)) # create the template var by adding to context context[self.context_var] = \ Book.objects.filter( # find all books for object content_type__pk = content_type.id, object_id = self.obj.resolve(context).id ) return '' def books_for_object(parser, token): """ Retrieves a list of books for given object {% books_for_object foo_object as book_list %} """ try: bits = token.split_contents() except ValueError: raise TemplateSyntaxError( _('tag requires exactly two arguments') if len(bits) != 4: raise TemplateSyntaxError( _('tag requires exactly three arguments') if bits[2] != 'as': raise TemplateSyntaxError( _("second argument to tag must be 'as'") return BooksForObjectsNode(bits[1], bits[3]) def book_form(parser, token): """ Adds a form to the context as given variable {% book_form as form %} """ # take steps to ensure template var was formatted properly try: bits = token.split_contents() except ValueError: raise TemplateSyntaxError( _('tag requires exactly two arguments') if bits[1] != 'as': raise TemplateSyntaxError( _("second argument to tag must be 'as'") if len(bits) != 3: raise TemplateSyntaxError( _('tag requires exactly two arguments') # get the form return BookFormNode(bits[2]) class BookFormNode(Node): """ Get the form and add it to the context """ def __init__(self, context_name): self.context_name = context_name def render(self, context): from books.forms import NewBookForm form = NewBookForm() # create the template var by adding to context context[self.context_name] = form return '' # register these tags for use in template files register.tag('books_for_object', books_for_object) register.tag('book_form', book_form) register.simple_tag(get_book_form_url)
Add this to your template
To start adding books to an object, add this code to your template and change my_awesome_object_here to the template variable name of your object.
<h2>Books</h2> {% load book_tags %} {% books_for_object my_awesome_object_here as books %} {% for book in books %} <a href="{{ book.get_absolute_url }}">{{ book }}</a> - {{ book.description }} {% endfor %} <h2>Add a book</h2> <form action="{% get_book_form_url my_awesome_object_here %}" method="post"> {% book_form as form %} {{ form }} <input type="submit" value="Go" /> </form>
You can get the template tags source code and the code from
the previous post at the
google code project page or by doing
svn co http://django-books.googlecode.com/svn/trunk books
in a directory on the python path.
Related posts:
- How to Write Reusable Apps for Pinax and Django Pinax is a collection of reusable django apps that…
- Django RequestContext Example Browsing other peoples’ code is a great way to learn…
- Quick Thumbnails in Django I normally like to write code myself instead of installing…