Django and NIH

Just so you know, Django is a smug, arrogant framework that doesn’t play nice with others. The developers are smug, arrogant assholes who don’t care what anyone else does or what other tools are available, and who always insist on doing things their way. Django absolutely refuses to support cool “standard” Python tools and libraries unless they were implemented first for Django. Just stay the hell away from it, and teach those goddamned Django people a lesson by doing so!

Or at least, that’s the impression you’d get from reading the rants some people periodically launch against it. I understand why this particular dead horse gets dragged out and flogged every once in a while (and I understand why, on several occasions, the flogging has been done by developers of other Python web frameworks), but understanding why it happens doesn’t make it any less wrong. And of course there’s an entry in the Django FAQ about why we’ve “reinvented” a number of things, and has been pretty much since day one, but for some reason people either don’t read it or just dismiss it out of hand.

So let me try to set the record straight.

NIH Syndrome

The “NIH” stands for “Not Invented Here”, and is a common ingredient of bad software projects — rather than looking at what’s available and figuring out what they can re-use, such projects ignore existing work and proceed to re-invent everything for their own use. If it didn’t come out of the project originally, it doesn’t get used.

From the outside, especially now, it’s easy to fling that accusation at Django: we have our own object-relational mapper, our own templating system, our own middleware system… it sure looks like we’re suffering from a major case of NIH. But that’s a misleading impression, and to understand why we have to go back a ways in time.

Django began its life a number of years ago and coalesced, one piece at a time, out of the needs of the developers here at World Online. The key word here is “a number of years”; components of Django predate a lot of the things we’re often accused of “reinventing”. That shoots a big, gaping hole in the NIH argument, because it’s really hard to use a third-party tool that doesn’t exist yet.

Moving forward

Django has certainly evolved a lot since then, and high-quality tools have come into existence and matured independently of Django, and — in my own admittedly biased opinion — I think we’re doing an OK job of appropriately using them as we go. For example:

In the Great Leap Forward from Django 0.91 to Django 0.95, we bundled PyDispatcher rather than implement our own internal communications.

Not long after the initial public release, we picked up support for running under WSGI servers.

servers. We’ve got a branch going right now to integrate SQLAlchemy as an option for ORM .

. We’ve pulled in SimpleJSON for object serialization.

From the earliest public releases, we’ve used standard third-party database adapter modules instead of writing our own.

We’ve gained an internationalization system that’s based on gettext .

. We’ve opened up our authentication system; you can now use any authentication source you want by writing a single, simple class that tells Django how it works.

I could keep going on and on about the various third-party tools and standards Django uses and all the ways you can integrate more stuff if you want to, but hopefully the above will be enough to indicate that anyone accusing us of having NIH blinkers is full of it. Nevertheless, there are two things that keep coming up over and over again…

WSGI middleware versus Django middleware

One thing people ask a lot (well, one particular person asks it a lot, at least) is why, since Django can speak WSGI, it implements its own middleware system instead of taking advantage of the existing ecosystem of WSGI middleware. This seems like classic developer arrogance, right?

Well, not really. If you want to use WSGI middleware instead of Django’s, then go for it — we won’t yell at you if use a WSGI gzip module instead of Django’s GzipMiddleware , for example.

The problem is that you can’t always use WSGI middleware or other common WSGI tools. Django is heavily committed to also working under mod_python; if nothing else, it’s the standard deployment setup here at World Online, and the one we recommend to our clients when we sell them Django-based applications. And mod_python, according to its official FAQ, doesn’t really do WSGI yet; if you need mod_python and WSGI, you need to go fetch a third-party module and set it up yourself.

It’s kind of hard to use WSGI middleware when you don’t have a WSGI server.

And it’s a very good argument in favor of Django having its own middleware system which implements common needs like content encoding, caching, error handling, etc. It’s also why Django has two slightly different entry and exit points — one speaks mod_python and the other speaks WSGI. It’s not fun or pretty to need that, but what are you gonna do?

Templating

It’s true that now there are approximately eleventy billion Python templating toolkits out there, and some of them are pretty darned good. So why does Django still have its own different templating system? Off the top of my head, I can think of a few good reasons:

Speed. Most Python templating systems are heavily based on XML , which means you get the overhead of XML processing on every request. For some situations that overhead isn’t significant, but when you start serving a few million hits you start noticing how long it takes to parse those templates. Django’s template language, on the other hand, can be tokenized using a single, short, compiled regular expression. That makes it blazing fast; to steal a line from the Rails guys, Django can render and return a page several times over while other templating systems are still doing XML sit-ups.

, which means you get the overhead of processing on every request. For some situations that overhead isn’t significant, but when you start serving a few million hits you start noticing how long it takes to parse those templates. Django’s template language, on the other hand, can be tokenized using a single, short, compiled regular expression. That makes it blazing fast; to steal a line from the Rails guys, Django can render and return a page several times over while other templating systems are still doing sit-ups. Flexibility. That’s another problem with tying yourself to XML — it gets ugly when you want output that isn’t an XML -ish or SGML -ish format. Django’s templating system, on the other hand, can and happily will output all sorts of formats that don’t involve any angle brackets at all. You want CSV ? You got it. You want plain-text email? You got it. You want LaTeX? You got it. XML would make all of those things harder for no good reason.

— it gets ugly when you want output that isn’t an -ish or -ish format. Django’s templating system, on the other hand, can and happily will output all sorts of formats that don’t involve any angle brackets at all. You want ? You got it. You want plain-text email? You got it. You want LaTeX? You got it. would make all of those things harder for no good reason. Balance. Designing a templating language means walking a fine line: you have to keep business logic cleanly separated from the templating system, allow presentational logic and keep the whole thing simple enough to be picked up by someone who’s not a professional programmer. Django’s templating system does a better job of this than most of the other Python template kits I’ve seen, so I’d vote to keep it on this factor alone.

It’s also kind of amusing that some people apparently like Django’s template system so much that they’ve built standalone versions of it for use elsewhere (even in other languages — there’s a templating system available now for Rails that uses identical syntax to Django’s).

Can we put this to rest, then?

There’s a big difference between NIH and “we looked at what was available already and didn’t find anything suitable”. There are a number of places where Django has chosen to do its own thing, but those have been informed choices, made with an understanding of what existing tools were available.

So could we stop flogging the dead horse?