The Python Web Framework

22 August 2006

Apparently, the unthinkable (in the Python microcosm, anyway) has happened over at SciPy’06 during Greg Wilson's software carpentry talk.

“Guido just pronounced: Django is the [Python] web framework

  • Won’t be part of the core, but will be as ‘standard’ as PIL or NumPy
  • This was not what I expected the outcome of my talk would be, but hey, I’ll take it
  • He hopes that Django and TurboGears will converge.”

For whatever this means, congrats to the Django team for getting this far!

I must say though that I'm not entirely happy with this; in fact I don't like that there's been a “decision” at all, even though I understand that many people have been pushing for it for many years. IMNSHO, the “pronouncement” has very much to do with the Django team being very successful at marketing their product, and not so much with its technological underpinnings.

I've personally been involved in a rather large project using (and patching) Django over the last six months, so I think I have a good enough background to present some objections. This isn't to say that Django isn't a good product—it's just that I feel that there's too much hype floating around.

The Architecture

Django is a monolithic system that implements all the layers of the web application stack. The Django authors are quick to say that that isn't a problem, because any piece (such as the ORM or the template engine) can be replaced by something equivalent if you want to do that. While that is true to some extent, if you do that, you could just as well not use Django in the first place. Once you've replaced the ORM, you've rendered the automatic administration interface useless, and you'll want to be careful with using things like the authentication subsystem, because that would still go through Django's ORM and thus bypass SQLAlchemy's management of database connections and transactions. (And while we're at it, no, Django doesn't do any kind of connection pooling, and transactions only got added in the 0.95 release.)

And if you replace the template engine, you'll miss out on all the functionality provided by template tags and filters, as well as easy integration of things like the I18N support or the free comment system, which are also powered by custom template tags.

What remains of Django when you replace the ORM and the template system is hardly worth the overhead of the framework. The URL dispatching, HTTP request/response objects, HTML form processing, basically all the components that really are at the core of a web application framework work okay (mostly) but aren't really all that spectacular, and you'd be well advised to look for a more light-weight implementation of that functionality. I'm not going to give a recommendation here, but you should probably look for stuff that plays well with WSGI.

What also bugs me about Django is the configuration. Granted, having configuration files written in Python is quite flexible. But did you know that you can't even run `pydoc` on either the Django framework or your application without having an environment variable set that points to the module containing your application's settings? Or if you'd like to use any of the Django subsystems, the very first thing you need to do is “from django.conf import settings; settings.configure(...)”, and only then can you go on importing what you actually need from Django. How Pythonic is that, really? Oh, and what all this implies is that you can run only one Django application per process (or per Python interpreter) because settings are basically just global variables.

The Object-Relational Mapper

In a few words, the Django ORM is underpowered. Especially when it comes to really taking advantage of the things that relational databases are good at, such as complex joins. If you're doing any non-trivial database access, you either end up with hand-coding the SQL, or with doing many more queries than necessary. The QuerySet API that was added in 0.95 is not bad at all, but it's still a far cry from what SQLAlchemy provides.

Also note that, despite how much the Django folks tout the “separation of concerns”, the API for defining the model has deep ties into the administration interface.

The Template Engine

I don't like having to do template audits to check whether all output is being properly escaped for safe inclusion in HTML. And apparently noone appreciates that task, as even Django itself has contained quite a number of places (the admin, for example) where no or too little escaping was performed. To be fair, there's a proposal about automatically escaping output in templates by Simon Willison, and after a ridiculous amount of debate (considering how obvious the benefits are), it seems like it even has a chance of being accepted.

And I definitely don't like having to write a template tag every time I need to call a function with arguments from a template, or do a “less than”/“greater than” comparison. There are no parameterizable macros, so you can't easily reuse template snippets that vary according to parameters, without resorting to writing a template tag that includes another template file. And consequentially, recursion in templates is not possible without custom tags either (but things like dynamically building a nested list of navigation items are really uncommon in web templating—only they're not.) Just look at the mess that are the templates and template tags for the admin interface. (But keep in mind that prior to version 0.91 the admin interface generated templates at runtime. So even the current complexity can be considered a vast improvement over the first public release.)

There was a comment by someone in the audience at the Google TechTalk on Django along the lines of “the Django template system doesn't scale down to the single developer,” or scale down to teams where the programmers are also those who write the templates. And indeed, it does not. Django templates are intentionally dumbed-down so that “a designer can wrap his head around them.” So it makes you jump through a lot of hoops if you happen to take on both the role of the programmer and that of the template author.

from __future__ import webframework

Guido stated that he wished that Django and TurboGears (the other major Python web framework) would converge. That is however highly unlikely. There's more than one approach to web application design, and for many sites, TurboGears may very well be the better alternative. Or Pylons. Or Quixote. Or Or your friendly neighbor's Python web framework.

Many of those frameworks have a design and vision that isn't compatible with any of the others. Just like Django, most of them were written because the developers were unhappy with the other options out there. In other words, they don't exist just because people have fun reinventing the wheel. Chances are that this particular “wheel” isn't quite there just yet.

So hopefully this pronouncement won't discourage anyone from developing new and better ways to write web applications. While it's pretty nice, Django certainly doesn't get it all right, and there's still a lot of room for better options.


  1. In “Django: nice and critical (article)”, someone says:

    15 June 2007

    I am a django fan and I am using it for a while and very successful in a couple of projects. But reading this article fortunately makes me take a step back and rethink some of the things and be a little more critical with the blindness that sometime …
  2. In “about:cmlenz - Logic in Templates”, Christopher Lenz says:

    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: