Using Django Inside the Tornado Web Server
Inspired by Eric Florenzano’s talk, Using Django in Non-Standard Ways (slides in PDF) at DjangoCon and the announcement of Tornado (tornadoweb.org), I decided to try building a small application using the Django Form library and Django ORM inside Tornado. The process proved easier than I expected, especially with Russell Keith-Magee being able to provide guidance on demand.
Step 1: Create Your Database
While Russell explained that it should be possible to get commands like syncdb running outside of a traditional Django project, it was outside the scope of this small experiment. Instead, I created a Sqlite database manually. For those of you that have forgotten how to do this, this will get you started:
# sqlite3 dev.db sqlite> CREATE TABLE message (id integer primary key, subject varchar(30), content varchar(250)); sqlite> insert into message values(1, 'subject', 'cool stuff'); sqlite> SELECT * from message;
Step 2: Write Your Application
With the database in place, you can create your application in a single file. We’ll call ours dj_tornado.py.
import sys import os import tornado.httpserver import tornado.ioloop import tornado.web # django settings must be called before importing models from django.conf import settings settings.configure(DATABASE_ENGINE='sqlite3', DATABASE_NAME='dev.db') from django import forms from django.db import models # Define your Model class Message(models.Model): """ A Django model class. In order to use it you will need to create the database manually. sqlite> CREATE TABLE message (id integer primary key, subject varchar(30), content varchar(250)); sqlite> insert into message values(1, 'subject', 'cool stuff'); sqlite> SELECT * from message; """ subject = models.CharField(max_length=30) content = models.TextField(max_length=250) class Meta: app_label = 'dj' db_table = 'message' def __unicode__(self): return self.subject + "--" + self.content # Define your Form class DjForm(forms.Form): subject = forms.CharField(max_length=100, required=True) content = forms.CharField() # Define the class that will respond to the URL class ListMessagesHandler(tornado.web.RequestHandler): def get(self): messages = Message.objects.all() self.render("templates/index.html", title="My title", messages=messages) class FormHandler(tornado.web.RequestHandler): def get(self): form = DjForm() self.render("templates/form.html", title="My title", form=form) def post(self): data = { 'subject':self.request.arguments['subject'][0], 'content':self.request.arguments['content'][0], } form = DjForm(data=data) if form.is_valid(): message = Message(**form.cleaned_data) message.save() self.redirect('/') else: self.render("templates/form.html", title="My title", form=form) # map the Urls to the class application = tornado.web.Application([ (r"/", ListMessagesHandler), (r"/form/", FormHandler), ]) # Start the server if __name__ == "__main__": http_server = tornado.httpserver.HTTPServer(application) http_server.listen(8888) tornado.ioloop.IOLoop.instance().start()
Step 3: Create Some Templates
As you have seen in the code above I am using 2 simple templates to render the responses. Tornado syntax is very similar to Django/Jinja templates so Django developers should feel right at home here.
<!-- index.html --> <html> <head> <title>{{ title }}</title> </head> <body> <ul> {% for message in messages %} <li>{{ escape(message.subject) }} -- {{ escape(message.content) }}</li> {% end %} </ul> <a href="/form/">Add</a> </body> </html>
<!-- form.html --> <html> <body> <form action="/form/" method="post"> {{ form }} <input type="submit" value="Submit" /> </form> </body> </html>
Step 4: Start Your Server
This is easy: # python dj_tornado.py
Step 5: Profit!
Point your browser to http://127.0.0.1:8888 and enjoy your toy Tornado application.
While this application itself doesn’t do much of anything exciting, it should give you a blueprint for how to use Django in “non-standard” ways and show you how to bring some of your familiar Django tools into different applications.
You can find the code example at http://bitbucket.org/yml/dj_tornado/. I would be glad hear your opinion about this approach.
Comments
Got something to say?
Our Products
Categories
- accessiblity
- code
- company news
- django
- gondola
- open source
- portfolio
- presentation
- pro tip
- review
- screencast
- seo
- software
- subversion
- trailmapping
- wordpress
Archives
- July, 2010
- June, 2010
- May, 2010
- April, 2010
- February, 2010
- December, 2009
- November, 2009
- October, 2009
Elsewhere
What we’ve been up to online
-
Just launched a Flask/App Engine mini-site we've been tinkering on http://emailed-me.appspot.com/
Pete, 14 hours, 52 minutes ago -
created repository Emailed-Me-
Pete, 14 hours, 59 minutes ago -
Our first iPhone development project hit the App Store last week and is already over 1k users! Check them out @takemyspot #iphone #geodjango
Pete, 3 weeks ago -
Love the new sites! RT @welikesmall: We just launched two new sites. http://post.ly/mGoq
Pete, 3 weeks, 1 day ago -
Pro tip: Using pip safely for automated deployment (no more pesky prompts) http://bit.ly/b5zsPa
Pete, 4 weeks, 1 day ago -
commented on justquick/django-mailfriend
Pete, 1 month ago -
RT @unbracketed: Excited to have @mitsuhiko joining us for some work this summer :)
Pete, 1 month ago -
New blog post: managing supervisord with upstart http://bit.ly/db3p5N
Pete, 1 month ago -
Troubleshooting OpenID is just like user/password. Except you have 5 of them and and you don't know which one is failing, and 3 login pages
Pete, 1 month, 1 week ago -
This gets very interesting around 42 min. Using javascript to snoop inside firewalled networks http://bit.ly/aNVPc5
Pete, 1 month, 2 weeks ago -
The final tally is in. 8 Lincoln Loopers attending DjangoCon. 3 US, 4 EU, and 1 NZ. Looking forward to it!
Pete, 1 month, 2 weeks ago -
Twitter / Dustin Curtis: I'm flying to Madrid tomor ...
Dustin Curtis travels to Berlin, Bangkok & Madrid in exchange for design services as the result of a late night tweet.
Pete, 1 month, 2 weeks ago -
created branch ubuntu-8.04 at lincolnloop/fab-pave
Pete, 1 month, 3 weeks ago -
created repository fab-pave
Pete, 1 month, 3 weeks ago -
pushed to master at lincolnloop/django-mailfriend
Pete, 1 month, 3 weeks ago


In my view using Django (or really any other normal WSGI framework) inside of Tornado is rather pointless. The advantage of using Tornado is that it does non blocking IO, however a Django request is going to block for it’s entirety, so you really don’t get anything by using this.
Yeah, the advantage of this in a production environment is debatable. I think it was an experiment in re-using Django bits outside of a traditional Django project more than anything else.
The ability to get any one of the Python micro-frameworks up and running quickly, only using the Django bits you need, is compelling. The techniques Yann uses here could be applied not only to Lightning, but anyplace you wanted to use Django modules.
But he’s not using Django’s request/response objects or it’s middleware handling or anything else related to the HTTP request. He’s only using the models and forms objects which, I think, are wholly unrelated to the asynchronous features that Tornado gives you.
I agree completely, but in my experience the longest portions of any web request are SQL queries, and those do block :)
Bret Taylor, said this about synchronous DB queries:
We experimented with different async DB approaches, but settled on
synchronous at FriendFeed because generally if our DB queries were
backlogging our requests, our backends couldn’t scale to the load
anyway. Things that were slow enough were abstracted to separate
backend services which we fetched asynchronously via the async HTTP
module.
http://groups.google.com/group/python-tornado/browse_thread/thread/9a08f5f08cdab108
Thanks for posting this, by the way, Yann!
I just wish that Django could be async like tornado someday….
In a post in my own blog http://trespams.com/2009/09/14/django-cherrypy-vs-tornado/ I compared Tornado WSGI with CherryPy.
Actually we’re using ngnix as reverser proxy and to serve media, that connects with one o more CherryPy servers that runs Django via WSGI.
With this configuration Tornado could server about 16% more connections that CherryPy.
You could ask me why this configuration, of course. We have found that this gives a lot of freedoom in the way we can configure our servers and scale the applications. With CherryPy the req/s was lower that with Apache+mod_python but it was good enougth and the CPU and Memory required was about 10%.
Acually we’re testing Tornado as a replacement of CherrPy. Pehaps we could use it as a microframeworks to act as a REST server or XML server, but for normal web applications our plans are to continue with Django.
vmqtmb, http://URBANWORSHIP.ORG , lose weight fast wxtrbao
numzcq, http://SCOREADVANCE.NET , ghnfzsc
pscolw, http://mercedesofsouthatlanta.com, How To Lose Weight Fast qheqppi