How to Write Django Template Tags
posted on January 22nd, 2009 by Greg Allard in Greg's Posts on Code SpatterTemplate 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…