Template Tags

If you've used the python-based web framework Django for any adequately sized project, you'll soon realise how excellent of an idea Django's template tags are.

Template tags, in brief, allow extending Django's templating capabilities to handle just about anything the designer throws at you. They also satisfy the criteria of being incredible easy to write; on most occasions, the designer will write the "tag" themselves.

Here's an example of a filter tag which converts text to lowercase:

def lower(value):
    """Converts a string into all lowercase"""
    return value.lower()

register.filter('lower', lower)

then used later in your template like this...

# greeting = "HELLO WORLD"
{% verbatim %}{{ greeting|lower }} # outputs "hello world"{% endverbatim %}

Nice. The filter tag is the simplest type of tag available. Other powerful tag types take arbitrary arguments as input well as complete blocks of your template[1].


Cactus is a static site generator written in python and uses Django templating engine to render its pages. The cactus docs for plugins touch on template tags but you'll need to know a little about Django and how Cactus works beforehand.

The problem is django looks through each of its "installed apps" for a template tag directory to load custom template tags (docs). Unfortunately since our project isn't a registered django app at configuration time, django won't know where to locate our tags come render time.

# pages/index.html
{% verbatim %}{% load my_tags %}{% endverbatim %} # assuming a plugins/my_tags.py exists

# will throw:  
# django.template.base.TemplateSyntaxError: 'my_tags' is not a valid tag library: Template library plugins not found, tried django.templatetags.plugins,django\_markwhat.templatetags.plugins

Fortunately, this is a pretty easy fix.

Creating your first custom template tag

1. Setup

For the purpose of this demonstration, create a template_tags.py file in your plugins folder[2].


In template_tags.py, let's create a simple function which takes python dictionaries and returns them in a JSON format.

# plugins/template_tags.py
import json

from django import template
register = template.Library()

def jsonify(value):
	return json.dumps(value)

register.filter('jsonify', jsonify)

2. Adding your project to the python path

Open plugins/__init__.py and add the following code. This also has the benefit of making your project path available to all plugins.

# plugins/__init__.py
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

3. Registering your template tags with django

While still in plugins/__init__.py, add the following code.

# plugins/__init__.py
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

from django.template.loader import add_to_builtins

So here, we've injected our custom templates tags into django itself using the add_to_builtins method. There are a couple of benefits doing it this way:

  1. It's much cleaner and easier than trying to alter django's INSTALLED_APPS settings.
  2. We don't need to create a templatestags directory for our project. Although you could if you wanted to.
  3. We don't have to use the {% verbatim %}{% load template_tags %}{% endverbatim %} template syntax in our template files as our tags will automatically be loaded at render time.

Though the potential side effects of using this method would be overriding builtin tags accidentally which in this case, I would then recommending have a unique naming convention for your tags.

4. Test it out

// pages/index.html
// context['user'] = { "name": "jim", "gender": "male" }
var user = {% verbatim %}{{ user|jsonify }}{% endverbatim %};

// should output: user = { name: "jim", "gender": "male "};

Very nice!

You can find additional documentation on custom templates tags from the official django site.

Happy templating!

  1. If you're just getting started with Django, the builtin tags documentation is a good read before you start writing your own custom template tags. ↩︎

  2. Creating a file specifically called template_tags.py in your plugins folder is not a strict requirement. ↩︎