How should I validate HTML in Django templates during the development process?
Good question. I haven’t done this myself, so hopefully there will be some better answers, but you might want to look into HTML validation middleware:
- http://djangosnippets.org/snippets/1312/
- http://lukeplant.me.uk/resources/djangovalidator/
- http://bstpierre.org/Projects/HtmlValidatorMiddleware/
“in all possible scenarios” might be too much to ask for, depending on your app. For example if you make the next Facebook, and are thus accepting huge amounts of user data every day, something will come in at some point that breaks the validity of a page on your site.
As validation errors don’t tend to destroy functionality, it might be an acceptable approach to check with some limited test data, then react to errors as they come up. I believe this is known as stupidity-driven testing.
One solution is to make a script that renders all the templates based on an input dictionary of variables test values.
The main logic to retrieve the list of variables defined in the templates is the following:
from django.template.loader import get_template
def extract_required_vars(node):
if not hasattr(node, 'nodelist'):
return []
var_names = []
for child_node in node.nodelist:
if isinstance(child_node, VariableNode):
var_names.append(child_node.filter_expression.token)
elif isinstance(child_node, ForNode):
var_names.append(child_node.sequence.var.var)
elif isinstance(child_node, ExtendsNode):
template = get_template(child_node.parent_name.var)
var_names.extend(extract_required_vars(template))
elif isinstance(child_node, IncludeNode):
template = get_template(child_node.template.var)
var_names.extend(extract_required_vars(template))
var_names.extend(extract_required_vars(child_node))
return var_names
required_vars = extract_required_vars(get_template('index.html'))
The script then checks that the variables defined in the templates are either in the project settings or in the dict provided by user as test input.
/path/to/project/templates/templates/allusers.html
-> ok: users, STATIC_URL
/path/to/project/templates/entrer-en-contact.html
-> ok: contactform, STATIC_URL
/path/to/project/templates/dest-summary.html
-> ok: STATIC_URL
-> missing: dest_username
More details in this blog post.
Alternatively, a roll-your-own approach to validating pages on your site during your usual unit testing process would look something like this:
- Go through your
urls.py
and generate as many possible URLs for the site as you can - Use the built-in Django test client to fetch each of those urls
- Validate them somehow (See perhaps Validate (X)HTML in Python)
Not sure if anyone’s done any of the work on this is a reusable way.
See django-extensions project, it has a built in template validator which can be run with a manage command like so:
python manage.py validate_templates
This only tries to load your template using django's template loader, so checks for things like missing tags. As long as it can create a Template object it will pass. Here is more documentation on get_template which is the method it calls.