March 30, 2009

Twisted + Django: It won't burn down your house.

It's actually really easy to make these two things work together. Since ~8.2.0 Twisted has had a WSGI container runnable from the command line. So here is how you run Django on a supported version of Twisted.web.

  1. easy_install Twisted
  2. easy_install Django
  3. Profit!
  4. django-admin.py startproject foo
  5. Create a myapp.py with the following code:

    from django.core.handlers.wsgi import WSGIHandler

    application = WSGIHandler()
  6. export DJANGO_SETTINGS_MODULE=foo.settings
  7. twistd -no web --wsgi=myapp.application
And there you have it. There are probably a few compatibility problems but this mostly seems to work just fine. I'll be working with some Django weenies to figure out what, if anything is broken.

So look, this is really AWESOME.

Updated (3/30/2009 4:09pm): Twisted tickets #3585, #3721 are problems on Twisted 8.2.0 but are fixed or should be fixed in Twisted trunk soon.

Updated (3/30/2009 6:34pm): Both of the above tickets are done.

7 comments:

Drew Perttula said...

How does this work with respect to concurrent requests? I bet django page calls don't return deferreds.

Is django expecting long requests to be run in separate threads or something? Does twistd --wsgi actually use multiple threads?

Cornbread said...

Looks like a great post. Can you elaborate more on the configuration. Do you host your entire project on wsgi?

I'm a bit unsure how this fits in with the project as a whole whether you're running a single twisted app with a regular django project or the whole project is run on twisted. TIA

agc said...

@Drew Yes, twistd --wsgi is using threads. If you look in the Twisted source in "twisted/web/tap.py", you can see "opt_wsgi" (the method that gives twistd the --wsgi functionality) is utilizing twisted.web.wsgi.WSGIResource, which, in turn, takes a threadpool.ThreadPool() instance as it's second argument.


@Cornbread The reason that I find this new wsgi very exciting is that now you can run Django *together* with several other Twisted Services, all running under one single Twisted Application. Your other Twisted Service may be some cool XMPP app - and combining Twisted's great XMPP functionality with Django leads to some awesome possibilities. People probably have many other useful use-cases as well.


-Alex Clemesha

orospakr said...

Hey, how does one handle /media for the admin interface (and other static files) with this arrangement?

I am not too familiar with Twisted Web, but the documentation for WSGIResource suggests that there may be no subresources, as everything is passed to the WSGI app...

DAn said...

I am trying to use twisted words xmpp with django. I need my django views to make requests to the xmpp server, wait for the reply in a deferred callback, and then return a response. This is easy to do with twisted web resources, but how do you do it with django views?

If it's not possible my current plan is to handle urls that require xmpp access with twisted, and all other views with django. But I'd much rather serve all views with django.

Thanks!

agc said...

@orospakr To handle media files just use "static.File" from "twisted.web" like so: staticrsrc = static.File(os.path.join(os.path.abspath("."), "mydjangosite/media")) and then add that resource to your root resource like so: root.putChild("media", staticrsrc)

@DAn the latter solution is probably the way you want to go, i.e. "handle urls that require xmpp access with twisted, and all other views with django". See here for an example of exactly how to do this: http://github.com/clemesha/twisted-wsgi-django/tree/master

David Underhill said...

This is pretty useful -- I suggest looking at this blog entry by Alex Clemesha for all the details (and example code) that you'll need to implement this.