Django on Twisted Web - Using the latest twisted.web.wsgi functionality

April 23, 2009

There are many reasons why you might want Django and Twisted to work together when building an application. The first and most obvious thing that comes to mind is that you want to combine the best of what Django does (it’s clean MVC functionality - in addition to amazing bits like the admin interface) with the best that Twisted has to offer (excellent support for protocols like XMPP, etc, and many other lower level networking niceties). Other situations, like simplifying your development environment when creating app that require reverse proxies because of Javascript’s same-domain policy, also come to mind.

The method and example that I’m providing in this article is Twisted Web WSGI based. An alternative way of ‘joining’ a Django instance and some Twisted code, as just mentioned, is to reverse proxy a least one part of the app (whether it be the Django part of the Twisted part). This was in fact the way I first went about solving this problem, but I hit up against a bug related to following redirects in the Twisted reverse proxy code (which seems to be nearly fixed, see here: http://twistedmatrix.com/trac/ticket/3384 ). It is worthwhile to mention that when I say ‘join Twisted and Django’, I mean run them under the same domain to adhere to Javascript’s same-domain policy, but I digress.

Because of recent work by some Twisted developers, running Django on Twisted is much easier, but still a bit under documented and bleeding edge (the relevant code is in the Twisted trunk - at the time of this writing Twisted’s release version is 8.2). A couple weeks back it was announced that because of work done at Pycon 2009, Django now runs correctly off code in the Twisted trunk.

A complete Django+Twisted WSGI example

Update (12/20/2009): The latest release of Twisted (9.0.0+) includeds all code needed to run the following example. Running off the Twisted trunk is not needed any more

I decided that I would share my current usage of Twisted on Django by way of a simple example. I put my example code up on github, so if you want to play around with it, get it like this:

git clone git://github.com/clemesha/twisted-wsgi-django.git

Here is my Django on Twisted Web WSGI example on Github if you just want to take a look at the code with pretty syntax highlighting and all that. In the twisted-wsgi-django project you will see 3 interesting things.

  1. The directory mydjangoproject, which is basically an extremely simple Django project, taken right from the Django documentation, to demonstrate a working Django instance. You would replace this with you real Django project if you wanted to see if all you own Django code does in fact run cleanly under Twisted.

  2. The file server.py which holds the Django<->Twisted WSGI code, as well as the Twisted server and application boilerplate code. To run the example you would type ./TwistedTrunk/bin/twistd -ny server.py.

  3. The file twresource.py which holds only Twisted Web code. You can see this as the simplest possible example of where you would start writing all your Twisted code - or if you have existing Twisted code, you can see how it gets plugged in together with a running Django instance.

Once you have ran ./TwistedTrunk/bin/twistd -ny server.py, navigate to http://localhost:8000/admin to verify that Django is running. If all bits of Django’s admin interface are working (including the css and images being there - which are being served up by an out-of-wsgi-band instance of Twisted Web’s static.File) then you know that all is well with Django and Twisted.

Now go to the url http://localhost:8000/google?q=somequery, which is a resource being handled completely by custom Twisted code. Behind the scenes it grabs a google query page using twisted.web.client.getPage. As you can see if you check the source of the file twresource.py, we are totally in Twisted land. This is where you can start plugging in some Twisted XMPP code, maybe start using Twisted’s Perspective Broker, or whatever else.

If you have an opinion on how to do this better or cleaner, please drop a note.