Django Templating: More Than Just Blocks by Christine Cheung

Presenter: Christine Cheung ( (@plaidxtine)

PyCon 2012 presentation page:




  • Intro to Templating
  • Effective Use of Built-In Tags
  • Extending Templates
  • Template Loading
  • What’s New

Intro to Templating

Django Templating 101

  • This is the End User Experience
  • Balance between power and ease
  • Design

Helpful tools

Folder and file structure

  • Keep templates in one place

Style guide

  • Think PEP 8 coding conventions
    • consistent spacing
  • {% load %} all template tags up top
  • try {# comment #} rather than <!-- this -->
    • also, {% comment %}{% endcomment %}

Effective Use of Built-In Tags

The Basics

  • Start with base.html

    <!doctype html>
        <title>{% block title %}demo{% endblock title %}</title>
    {% block content %}{% endblock content %}
  • Then have pages inherit from it

    {% extends "base.html" %}
    {% block title %}the foo page{% endblock title %}
    {% block content %}
        <div id="foo">
            this is a bar.
    {% endblock content %}

Common blocks

I use these in practically every project:

  • title
  • meta_tags, robots,
  • extra_head (CSS, etc.),
  • content
  • extra_js (so that JavaScript can go at bottom of page which improves page-load time)

Block practices

  • End your block structures
    • {% block title %}foo{% endblock title %}
    • instead of {%block title %}foo{% endblock %}
  • Can’t repeat blocks
  • Don’t “over block”

Including templates

  • {% include "snippet.html" %}
    • great for repeating template segments
  • try not to include in an include – gets confusing


  • Tend to be objects passed from a view
    • Modify objects with filters
      • {{ variable | lower }}
    • Loop through etc. using tags
      • {% if variable %}foo{% else %}bar{% endif %}
      • {% for entry in blog_entries %}<h2>{{ entry.title }}</h2><p>{{ entry.body }}</p>{% endfor %}
    • You can also create your own filters and tags (see Django docs on custom template tags and filters)


By default, Django’s security is rather solid on the template side of things...

  • but if you use safe or {% autoescape %}
    • * make sure you sanitize the data! *


Name {% url %} tags as much as possible

  • define URL patterns in
    • url(r'^foo/$', foo, name="foo"),
    • <a href="{% url "foo" %}">foo</a>

{{ STATIC_URL }}css/style.css

  • Not /static/css/style.css


For heavy form action, take a look at:

{% include form.html %}
  • as_ul (docs) makes more sense than as_p or as_table

More than one way

There are multiple ways to accomplish the same task.

No ultimately right or wrong way

  • use what suits you or your team

An example

The long way:

{% if %}
    {{ }}
{% else %}
    {{ foo.baz }}
{% endif %}

or the shorter way:

{% firstof foo.baz %}

Extending templates

Custom Tags and Filters


Given that we have template tags in demo/templatetags/

{% load demo_utils %}

Making a Custom Filter

from django import template
register = template.Library()


def cut(value, argument):
    # remove passed arguments from value
    return value.replace(argument, '')
{{ foo|remove:'bar' }}
def lower(value):
    # lowercased value with no passed arguments
    return value.lower()
{{ foo|lower }}

Making a Custom Tag

Tags are a bit more complex

  • two steps: compiling and rendering

Decide its purpose

  • but start simple

better to have many tags that do many things rather than one tag that does many things

A Simple Example

    It is now
    {% current_time "%Y-%m-%d %I:%M %p" %}

Simple Tag

from django import template

register = template.Library()

def current_time(format_string):
    except UnicodeEncodeError:
        return 'oh noes current time borked'

Nodes and Stuff

import datetime
from django import template
register = template.Library()


def do_current_time(parser, token):
        tag_name, format_string = token.split_contents()
    except ValueError:
        msg = '%r tag requires a single argument' % token.split_contents()[0]
        raise template.TemplateSyntaxError(msg)

class CurrentTimeNode(template.Node):
    def __init__(self, format_string):
        self.format_string = str(format_string)

    def render(self, context):
        now =
        return now.strftime(self.format_string)

Easier Template Tag Creation


  • makes it simple to define syntax for a tag


  • class-based template tags
  • extensible argument parse for less boilerplate


Do not write a template tag that runs logic or at worst, even run Python from a custom tag

  • it defeats purpose of a templating language
  • dangerous
  • difficult to support

Loading templates

Template loading logic

Use cases

TEMPLATE_LOADERS setting (Django docs)

from django.conf import settings
from django.template import TemplateDoesNotExist

def load_template_source(template_name, template_dirs=None):
    for filepath in get_template_sources(template_name, template_dirs):
            # load in some templates yo
        except IOError:

    raise TemplateDoesNotExist(template_name)

Replacing the templating engine

You can replace the built in templating engine

But why?

  • More familiar with another templating language
  • Performance boost
  • Different logic control and handling

but you risk “frankensteining” your project.

Jinja2 and Django and You


  • functions callable from templates - don’t have to write tags and filters
  • loop controls - more powerful flow control
  • multiple filter arguments
  • slight performance increase


  • more dependencies and overhead
  • extra time spent on development and support
  • risk putting too much logic in templates
  • minimal speed increase

Speeding Up Templates

Cache template loader


  • compiles template files


  • from Adrian Holovaty (one of the creators of Django)
  • flattens template files

but also remember other bottlenecks...

New in Django 1.4

Django 1.4 release notes

Custom project and app templates

Else if