Primary image for Using Django Inside the Tornado Web Server

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

<span class="n">sqlite</span><span class="o">&gt;</span><span class="w"> </span><span class="k"><span class="caps">CREATE</span></span><span class="w"> </span><span class="k"><span class="caps">TABLE</span></span><span class="w"> </span><span class="n">message</span><span class="w"> </span><span class="p">(</span><span class="n">id</span><span class="w"> </span><span class="nb">integer</span><span class="w"> </span><span class="k">primary</span><span class="w"> </span><span class="k">key</span><span class="p">,</span><span class="w"> </span><span class="n">subject</span><span class="w"> </span><span class="nb">varchar</span><span class="p">(</span><span class="mi">30</span><span class="p">),</span><span class="w"> </span><span class="n">content</span><span class="w"> </span><span class="nb">varchar</span><span class="p">(</span><span class="mi">250</span><span class="p">));</span>
<span class="n">sqlite</span><span class="o">&gt;</span><span class="w"> </span><span class="k">insert</span><span class="w"> </span><span class="k">into</span><span class="w"> </span><span class="n">message</span><span class="w"> </span><span class="k">values</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;subject&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;cool stuff&#39;</span><span class="p">);</span>
<span class="n">sqlite</span><span class="o">&gt;</span><span class="w"> </span><span class="k"><span class="caps">SELECT</span></span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="n">message</span><span class="p">;</span>
</pre></div>


	

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 the author

Yann Malet

Yann builds and architects performant digital platforms for publishers. In 2015, Yann co-authored High-Performance Django with Peter Baumgartner. Prior to his involvement with Lincoln Loop, Yann focused on Product Lifecycle Management systems (PLM) for several large …