← All Posts · ← Previous · Next →

Django vs. Cheetah: 1-0

January 31, 2006 — originally posted on artima.com


Encouraged by Fredrik Lundh, I took a look at Django templating, separate from the rest of Django. This works fine, except there's a mysterious environment variable DJANGO_SETTINGS_MODULE that is somehow required. That may be fine for framework users, but it's a bit harsh if all you want to do is use the templating library. Setting it to empty didn't help. I ended up uing this hack:

import os
os.environ["DJANGO_SETTINGS_MODULE"] = "__main__"

from django.core.template import Template

With that out of the way, I managed to run this program:

t = Template("<h1>Hello {{name}}</h1>")
print t.render({"name": "Phillip"})
print t.render({"name": "Adrian"})

This is nice! The output of course is:

<h1>Hello Phillip</h1>
<h1>Hello Adrian</h1>

Unfortunately I had trouble installing Django for the Python 2.5 alpha that I've got installed; it uses the fancy new ez_install stuff, which is great when it works, but there's no Python 2.5 download of setuptools on PyPI yet, so it doesn't.

I tried the same exercise using Cheetah. Not too different:

from Cheetah.Template import Template
names = {"name": "Tavis"}
t = Template("<h1>Hello $name</h1>", searchList=[names])
print t
names["name"] = "Ian"
print t

with the following output:

<h1>Hello Tavis</h1>
<h1>Hello Ian</h1>

(Ironically, Cheetah also failed under Python 2.5 -- Python 2.5 inadvertently (I believe) changes the syntax that's allowed before "from __future__ import ..." to disallow assignment to __author__ and __version__. That was easier to fix though -- commenting out the "from __future__ ..." line was sufficient.)

Side-by-side Comparison

(BEWARE! I haven't used either system to build a real website yet. I'm just looking at the API and templating language designs.)

Django definitely feels more "modern" than Cheetah. The templating languages are fairly similar, with Django writing {{foo.bar}} where Cheetah writes $foo.bar or ${foo.bar} for variable interpolation (== substitution). The biggest difference is that Cheetah allows pretty much arbitrary Python call syntax, e.g. ${foo.bar('hello', $name, 42+42)}. Yes, you have to prefix variable references in the argument list with another $, and there are confusing rules about when the $ is optional. Django only allows names separated by dots, using the old Zope trick of trying x['y'], x.y and x.y() when the input is {{x.y}}. When y looks like a number, it'll even try a sequence index, e.g. {{x.4}} means x[4].

(Aside: something similar is also found in web.py, but there it bothers me, because it's invoked from normal-looking Python code. E.g. foo["x"] and foo.x are equivalent, when foo is a "Storage" object. But this leaves me wondering, what does foo.keys mean? The keys method or the value stored under "keys"? Zope 2 was similarly confusing with implicit acquisition.)

A big difference: if Django doesn't find a name, it inserts nothing; but Cheetah raises an exception. ISTM that Django is more user-friendly here, even if its approach could be considered error-prone (typos are easily missed since they simply suppress a small bit of output). In my experience, missing variables are very common in substitution data, and Cheetah requires you to provide explicit default values in this case.

Both templating languages also have a "statement" syntax to complement their "expression" interpolating syntax. In Django, this is written as {% keyword %} while in Cheetah you use #keyword. Here I initially found Cheetah a bit more readable, since it resembles C preprocessor syntax:

#if $name
<h1>Hello $name</h1>
#else
<h1.Hello there</h1>
#end if

This is written in Django as:

{%if name%}
<h1>Hello {{name}}</h1>
{%else%}
<h1>Hello There</h1>
{%endif%}

which is harder on the eyes and prints more unnecessary whitespace.

But then I stumbled upon Cheeta's inline form, which is pretty unreadable due to the symmetric delimiters:

# if $name # <h1>Hello $name</h1> # else # <h1>Hello There</h1> # end if #

Both languages have tons of other statement-level constructs, to do loops, set variables, invoke other templates, define blocks that can be used by other templates, and more. I haven't explored this much yet, but they both seem to cover a similar terrain. I guess this is what template authors actually need; or perhaps it points to some common ancestor in PHP or JSP?

If you need your variable interpolations to be HTML-escaped (replacing "<" with "&lt;" and so on), Cheetah lets you specify a default filter in the template (#filter) or when the template is created in Python code. In Django you must add a pipeline to the interpolation syntax, like this: ${foo.bar|escape}. Both support various other filters as well, with Django really going wild. I'm somehow surprised that HTML-escaping isn't the default -- failing to HTML-escape data is the number one vulnerability leading to XSS attacks. And in theory you should almost never need to provide HTML for interpolation: you're supposed to invoke HTML fragments using #include or {%include%}. Cheetah at least provides a way to make HTML-escaping the default filter throughout a template.