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.
