So, you need to integrate a service with your website. That could be your web analytics tool, Typekit, Google's or Yahoo's webmaster tools, whatever. The thing is, you have to edit a small amount of HTML on the production server.
Generally you never do some coding on the production server. You fix things on your development machine and push the changes to the server. But sometimes you don't have the same setup on your local machine than on your server. That's why the local_settings.py trick is so useful: you keep it out of source control, and you never have any conflict between your different setups. And you try to import the local settings, silently failing if the module doesn't exist.
It's exactly the same case here: you just want to set up something on the server but not on your local machine. A simple solution would be to do {% include 'head.html %} and keep head.html out of source control, but:
- You don't need it on the development machine
- You'll get error pages if you have TEMPLATE_DEBUG=True, which is almost always the case during development
- You might forget to add the (even empty) template on the production server and therefore get a few error emails at each visit
So, what about extending the local_settings thing to templates? You just need a template tag that would include another template and silently fail if it doesn't exist, whether you're on debug or production mode. Here you go:
from django import template
register = template.Library()
class IncludeNode(template.Node):
def __init__(self, template_name):
self.template_name = template_name
def render(self, context):
try:
# Loading the template and rendering it
included_template = template.loader.get_template(
self.template_name).render(context)
except template.TemplateDoesNotExist:
# Let's return nothing
included_template = ''
return included_template
@register.tag
def try_to_include(parser, token):
"""Usage: {% try_to_include "head.html" %}
This will fail silently if the template doesn't exist. If it does, it will
be rendered with the current context."""
try:
tag_name, template_name = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError, \
"%r tag requires a single argument" % token.contents.split()[0]
return IncludeNode(template_name[1:-1])
Then, in your templates (assuming you've called your module include_tags):
{% load include_tags %}
<head>
...
{% try_to_include "head.html" %}
</head>
If the third-party service needs an extra <meta> tag, this would be the way to go. I have two of these inclusions on each page: one in the <head> section, and one at the end of the <body> section.
That's one of the rare cases when silent errors are convenient. I wonder if there are other (and better) approaches though.
, Bruno Renié’s weblog
Comments
#1 June 10, 2010 — Philgo20
Thanks for the time saver, will try that for sure.
#2 June 21, 2010 — Daniel
Great job :)
Thanks
Add a comment
Comments are closed for this entry.