Extending templates

(Originally posted here by Simon Willison on 6th August 2008)

Django's template inheritance mechanism allows templates to extend other templates and replace named blocks within them. See here for a full explanation: ​http://www.djangoproject.com/documentation/templates/#template-inheritance

This feature becomes even more powerful when coupled with Django's template path concept, as discussed by Jeff Croft in this article: ​http://jeffcroft.com/blog/2008/aug/05/default-templates-django/

A frequently requested feature is the ability to provide an over-ride template that also extends itself. Consider the following:

# In settings.py TEMPLATE_DIRS = ('/var/templates/default', '/var/templates/mysite') # In default/homepage.html BIG COMPLEX TEMPLATE HERE {% block stylesheets %}<link rel="stylesheet" type="text/css" href="styles.css">{% endblock %} MORE BIG COMPLEX TEMPLATE HERE # In mysite/homepage.html {% extends "homepage.html" %} {% block stylesheets %}<link rel="stylesheet" type="text/css" href="mysite-styles.css">{% endblock %}

In other words, we want mysite/homepage.html to reuse default/homepage.html almost entirely, only replacing the stylesheets named block.

The above won't work - Django will throw confusing errors.

It turns out it IS possible to get this to work, if you're willing to do some devious tricks with your TEMPLATE_DIRS setting. Consider the following:

# In settings.py TEMPLATE_DIRS = ('/var/templates/default', '/var/templates/mysite', '/var/templates') # In mysite/homepage.html {% extends "default/homepage.html" %} {% block stylesheets %}<link rel="stylesheet" type="text/css" href="mysite-styles.css">{% endblock %}

This will do what we want it to do.

The trick is very simple - we add a new directory right at the end of TEMPLATE_DIRS which is the parent of all of the other directories. This has the effect of making every template file within our system uniquely addressable. Most of the time we will use the normal paths, but in the special case of wanting to extend a template with an over-riding version of itself we can reference its parent's full, unambiguous template path in the extends tag.

An alternative approach without using the parent directory trick: ​http://github.com/stephenmcd/django-overextends