Saturday, March 28, 2009

The Template Made Me Do It

I've been doing a little Django lately. Django's template language isn't Python; it's a somewhat Pythonic template language, and it's limited by design. At first, it frustrated me; after a brief battle, it surprised me.

My template was pretty simple: generate a monthly calendar page. Every day gets the same HTML, except for three special cases: first Wednesday of the month, other Wednesdays, and all Fridays.

In my first version, I passed a list of objects in the context. The template for-looped through the list, and did things like

{% ifequal d.isoweekday 3 %}

All by itself, that's mildly evil - the hard-coded magic number, though I can probably remember that isoweekday() starts counting at Monday == 1. Then I started nesting the if-else tags, and things got messy quickly. The Wednesday case, the Friday case, the first-Wednesday case: frustration. I wanted Python at my fingertips, not this crippled template language.

Which, of course, was the answer. I needed better abstractions for the template, and Python was the right place to create them. I subclassed and added the methods I needed: is_wednesday(), is_first_wednesday(), is_friday(), is_special()

Which let me write reasonable template code like

{% if d.is_special %}
    {% if d.is_first_wednesday %}

And then the surprise: I realized that fixing the messy template had also made my Python code cleaner. I ended up with a nice little app-specific date class, unit tests and everything. That was the right thing to do, but I hadn't bothered till I needed it for the template. The limitations of the template language drove the refactoring.

And that makes me think that limiting the template language was a very good idea indeed.

No comments:

Post a Comment