Logic in Templates

21 June 2007

Going through my referrer list, I found the blog post “Django: nice and critical (article)”, which is in response to my own rant about Django, and among other things, contains the following:

[…] the template approach of Django is in my eyes a very good one, we (also as developers) don’t want all the power of python in the template, it would just get us into other problems, that other known languages have.

I hear this point of view from time to time, and would like to respond.

I'm assuming the reference to “other known languages” is aimed squarely at the PHP camp, but it could just as well refer to a large number of other web development environments. In any case, the concern seems to be that mixing logic into templates is a bad thing. And that consequentially, limiting the amount of logic you can put in templates is a feature, not a limitation.

The problem is this: templates are all about applying logic to otherwise static files. You have sections that are processed conditionally, sections that are repeated a number of times, sections that override other sections inherited from other templates, etc. Django templates have those features. 99% of template engines have those features. So that obviously isn't the point here.

Logic in Django Templates

The point seems to be what kind of strings you can put in your condition or loop expressions. Django provides a mini expression language for this. In fact, the various template tags (including your custom ones) all need implement their own mini languages.

There is no guaranteed consistency in the language used between tags here, every tag parses its argument string as it sees fit. Oh, and instead of simply allowing template authors to call functions, Django templates use “filters”, which again have their own custom ways of parsing their parameters. Personally, while I have worked a lot with Django templates at work for some time now (yes, even though I enjoy ranting about Django, I am a Django user, and I even try to contribute patches back to the project whenever it makes sense), I do have to keep the Django template language reference open all the time to look things up. But I digress.

Django does allow your template expressions to call functions, just no functions that require arguments. Except if you wrap your function in a filter, and pass the arguments in a different way than you would in Python. Django templates also provide attribute and item access, both using “dotted notation”. What it also doesn't support, among many other Python language features, are operators.

So, for example, if you wanted a different presentation of a list of items depending on the length of the list, you can't just write:

  {% if len(items) < 3 %}
  {% else %}
  {% endif %}

Instead, you need to write your own little template tag (say {% if_length_less_than items 3 %}), which moves the use of those unsupported language constructs into the backend Python code.

Templates Need Logic

If templates didn't need any logic, you could get away with serving static files, using server-side includes, or simply applying Python string interpolation. But templates do require logic—it's what they call “presentation logic”. The more complex, interesting, and user-friendly a website gets, the more logic you need in the presentation layer.

If you can check a simple boolean condition in a template, why shouldn't you be able to do conditional processing based on the comparison of two numbers? Why shouldn't you be allowed to invoke a function that requires a parameter?

Are you afraid that your template authors are going to pull all the business logic into the templates, creating a huge unmaintainable mess of a system? Well, in that case you should probably also be concerned about your programmers doing the same kind of thing, only in the application code. You may need to reexamine your hiring process, instead of choosing a template engine that artificially limits the kind of logic that can be performed in the presentation layer.

For me, it boils down to this: do you really want to use a template engine that assumes you or your coworkers can't be trusted?

Why Not Just Allow Python in Templates?

Seriously, if we were talking about putting C++, Java, or C# code in templates, I'd wholeheartedly agree that that'd be a bad idea. But we aren't. We're talking about Python code here. If there's a programming language you'd let relative newcomers implement simple logic with, wouldn't that language be Python?

How could a custom, sparingly documented, somewhat inconsistent, and mostly unproven (compared to Python) mini expression language be any better for template authors? Or even for programmers who already know Python but also work on the templates (which I suspect is the case for most Django projects out there)?

In my humble opinion, this kind of “dumbed-down” templating results in only one thing: more lines of code in the application modules, lines of code that are really only about presentation, and should be in the templates. And frustration every single time you need to add those lines.


  1. In “about:cmlenz - More on Logic in Templates”, Christopher Lenz says:

    20 July 2007

    My Logic in Templates post from a couple of weeks ago generated a couple of responses, and as expected the topic is very controversial.
  2. In “about:cmlenz - Automatic Escaping is Not a “Newbie Feature””, Christopher Lenz says:

    1 August 2007

    (I'll resist commenting on the “it feels like making Django not trust us any more” line, which I find kind of ironic, personally. Anyway…)