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.