Integrate Tornado in Django
Tornado is a nice python WSGI-compliant web server developed by guys at FriendFeed. It’s primarily thought as application server for python web frameworks and according to FriendFeed benchmarks, it’s blazing fast thanks to its non-blocking connections.
UPDATE: For more performance info, James Abley pointed me to a very complete benchmark of available Python asynchronous webservers. It looks like Tornado is a real monster of concurrency.
There are already some how-to’s on the web on plugging Django web framework into Tornado webserver. A quick recap:
- A tutorial on Tornado, Django and nginx by Jeremy Bowers.
- How to import django framework inside a Tornado project by Lincoln Loop.
- A snippet by lawgon.
My approach is slightly different as I wanted to run Tornado using Django management command-line interface.
The 3 easy steps are:
- Add Tornado module to your django setup. If you use buildout, add Tornado git checkout to buildout.cfg using minitage.recipe.fetch recipe, like this:
[buildout] ... parts = ... tornado django ... [tornado] recipe = minitage.recipe.fetch urls = git://github.com/facebook/tornado.git | git | | ${buildout:parts-directory}/tornado [django] recipe = minitage.recipe.scripts initialization = import os os.environ['DJANGO_SETTINGS_MODULE']='project.settings.development' scripts = django eggs = Django ... entry-points= django=django.core.management:execute_from_command_line extra-paths = ${buildout:directory} ${tornado:location} ...
- Next, create a command-line extension hierarchy in your project’s main app:
$ mkdir project/myapp/management $ touch project/myapp/management/__init__.py $ mkdir project/myapp/management/commands $ touch project/myapp/management/commands/__init__.py
- Last, add a runtornado.py script in project/myapp/management/commands/ folder with the following content:
from django.core.management.base import BaseCommand, CommandError from optparse import make_option import os import sys class Command(BaseCommand): option_list = BaseCommand.option_list + () help = "Starts a Tornado Web." args = '[optional port number, or ipaddr:port]' def handle(self, addrport='', *args, **options): import django from django.core.handlers.wsgi import WSGIHandler from tornado import httpserver, wsgi, ioloop sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0) if args: raise CommandError('Usage is runserver %s' % self.args) if not addrport: addr = '' port = '8000' else: try: addr, port = addrport.split(':') except ValueError: addr, port = '', addrport if not addr: addr = '127.0.0.1' if not port.isdigit(): raise CommandError("%r is not a valid port number." % port) quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C' def inner_run(): from django.conf import settings print "Validating models..." self.validate(display_num_errors=True) print "\nDjango version %s, using settings %r" % (django.get_version(), settings.SETTINGS_MODULE) print "Server is running at http://%s:%s/" % (addr, port) print "Quit the server with %s." % quit_command application = WSGIHandler() container = wsgi.WSGIContainer(application) http_server = httpserver.HTTPServer(container) http_server.listen(int(port), address=addr) ioloop.IOLoop.instance().start() inner_run()
To run your tornado webserver, you just need to call your usual management program like manage.py with runtornado command, with the same syntax as runserver. In my case, I just run production server using supervisord, with a command like this:
$ ./bin/django runtornado --settings=project.settings.production 8000
If you found this quick how-to useful, remember to follow me on Twitter or subscribe to my feed for more django tips.
Related posts:

