Using Django Inside the Tornado Web Server

Posted in
Code, Django

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.

Yann Malet
About Yann Malet
Also known as yml, you can usually find Yann hanging on django's IRC channels. He contributes to a number of open source apps in the Django ecosystem. Yann is passionated about building well architectured performant ...
View Yann's profile
blog comments powered by Disqus