Yasser Souri
Yasser Souri

Reputation: 1957

How to parse Django templates for template tags

Situation

I'm writing a checker program that checks Django templates. For example I want to check if all Django templates that use url template tag, use it with quotes on first parameter so that it is Django 1.5 compatible. Also I want to check that they have included {% load url from future %} in their templates.

For example if my program parses the following Django template, I want it to raise an exception.

{% extends 'base.html' %}
<td>
  <a href="{% url first second %}">
  </a>
</td>

But this template should get parsed without exception.

{% extends 'base.html' %}
{% load url from future %}
<td>
  <a href="{% url 'first' second %}">
  </a>
</td>

I'm not limited to this simple example. I have other parsings to do. For example I want to check how many load template tags are present in the template.

Question

How can I elegantly solve this parsing problem?

Code

Please show me some code that can solve the example I mentioned. I want to detect whether {% load url from future %} is in the code. Also I want to check every url template tag and check if the first argument is quoted.

Bonus:

Upvotes: 9

Views: 4079

Answers (3)

davidtingsu
davidtingsu

Reputation: 1180

You can also use the compile_string method.

 >>> from django.template.base import *
 >>> settings.configure()
 >>> compile_string("<a href='ab'></a>{% cycle 'row1' 'row2' as rowcolors %}", None)
 >>> [<Text Node: '<a href='ab'></a>'>, <django.template.defaulttags.CycleNode object at 0x10511b210>]

The compile string method is utilized by the Template class and is the method used to produce the node list. Tested in Django 1.8 Alpha.

https://github.com/django/django/blob/1f8bb95cc2286a882e0f7a4692f77b285d811d11/django/template/base.py

Upvotes: 4

imposeren
imposeren

Reputation: 4392

Next code still uses django, but it can check if syntax is correct:

>>> from django.template import Template
>>> from django.template.defaulttags import URLNode
>>> t = Template("{% load url from future %}\n{% url projects_list company.slug %}")
>>> for node in t.nodelist:
...     if isinstance(node, URLNode):
...         for arg in node.args: print(arg)
... 
company.slug
>>> t2 = Template('{% load url from future %}\n{% url "projects_list" company.slug }')
>>> for node in t2.nodelist:
...     print(node)
... 
<django.template.defaulttags.LoadNode object at 0x32145d0>
<Text Node: '
{% url "projects_list" c'>
>>> 

As you see last node is not URLNode

Upvotes: 3

Aya
Aya

Reputation: 41950

You say...

I want to check if all Django templates that use url template tag, use it with quotes on first parameter so that it is Django 1.5 compatible.

...and...

I don't want to use regular expressions.

...because...

the result of that might become a huge spaghetti code

...but, frankly, writing a parser from scratch is likely to be even messier than using a regular expression. I don't see what's so messy about a regex as simple as something like...

"{% *url +[^']"

...and I doubt there's a non-regex-based solution that's as terse as that.

With regards to...

Also I want to check that they have included {% load url from future %} in their templates.

If your intention is to ensure Django 1.5 compatibility, this is pointless. According to the Django 1.5 release notes, the new-style url tag syntax is enabled by default, so the line {% load url from future %} won't have any effect.

And in versions prior to 1.5, it's much simpler just to put...

import django.template
django.template.add_to_builtins('django.templatetags.future')

...at the bottom of your settings.py and be done with it. :-)

Upvotes: 9

Related Questions