Database Django Templates

August 30, 2010

The MyBandSite product has multiple websites running on the same codebase. These websites all have different styling and use Django's sites framework to store their information in the same database.

Most of the site templates are stored on disk as normal Django templates, and are therefore picked up using the normal Django template functionality. In order to style the sites differently, I put the top level template.html file into the database, and use a custom template loader to pull it out on request. This in effect means that any of the default templates can be overridden, simply by creating a template with the same name in the database. As the templates are linked to a specific site, they'll only override that one site's templates and will not affect the other sites running on the same source and database. This also allows anyone with access to the admin site to maintain custom templates, and they don't need access to the file system. Performance hasn't been a problem.

I was new to Django when I developed this, so I ended up copying in the django-databasetemplateloader code into my project, and changing it a bit to make it work. (This project now appears to have evolved into http://packages.python.org/django-dbtemplates/overview.html)

Problem

I now have the situation where I want to test a new style for my site. How can I do this without affecting the live site? I want a test site that has the same data (i.e the SITE_ID in settings.py remains the same), but has different templates?

Solution

The solution is to customise the template loader. As it's in my project, I can change it at will. In this case I took the existing loader.py and copied it to loader_test.py. I then found the code that looked for the template in the database and made sure it prefixed the template name with TEST_, just for the select on the database. If this isn't found, then it falls back on the normal template name for looking in the file system.

Here's the line I added to load_template_source:

template_name = "TEST_%s" % template_name

Once this is done, all that need to be done is to add this template loader at the top of TEMPLATE_LOADERS in the settings.py:

TEMPLATE_LOADERS = (
    'MyBandSite.dbtemplates.loader_test.load_template_source',
    'django.template.loaders.filesystem.load_template_source',
    'django.template.loaders.app_directories.load_template_source',
)

So, all templates prefixed with TEST_ apply to the sites configured with the loader_test template loader, whilst normal live sites pick up the normal template names as they use the standard loader.

References