Rapid Development with TurboGears

Here’s how to develop a Web application the easy way — with Python and TurboGears

Over the past year, a growing number of “next generation
Web frameworks” have cropped up, promising to make you more
productive, make your code more maintainable, and make your project
more fun. And in nearly all of the cases, the frameworks deliver on
the pledges, eliminating the drudgery, complexity, and
laboriousness of developing Web applications. Famously,
Ruby has Rails, and
Perl has Catalyst.
Now, Python has "i">TurboGears ( "story_link">http://turbogears.org/). Buckle up! It’s
gonna be an exciting ride.

Undoubtedly, the question on your mind is, “What makes
TurboGears special?” After all, there are a lot of great
frameworks to choose from. For example, Ruby has Rails.

Rails deserves a lot of credit for moving Web development
forward. Rails offers a well-integrated stack of libraries to
handle everything from object-relational mapping (ORM) to
HTML templates, and its philosophy of
“convention over configuration” highlights how truly
monstrous a Struts XML configuration really
is. Equally important, Rails includes built-in support for the
Model-View-Controller paradigm, so
there’s no need to reinvent the wheel. You can jump on Rails
and roll.

But TurboGears offers many of the same innovations as Rails, and
goes further. For instance, TurboGears includes "i">SQLAlchemy, the best ORM in any dynamic scripting
language. And, of course, TurboGears is written in Python, so
Unicode support comes free, and Python’s vast array of
libraries is at your disposal. Better yet, TurboGears isn’t a
monolithic project.

Rails is a single project built from top to bottom by a single
team. In comparison, TurboGears is a suite of libraries developed
by various teams around the world, which are tested, integrated,
and packaged together by the TurboGears developers. In fact, one
TurboGears developer describes the framework as “the
Ubuntu of Python Web frameworks.” The
simile is apt: TurboGears can leverage the many innovations made
outside the project itself. (And if there’s one thing you can
be sure of in the open source world, it’s that a lot of
innovation happens outside of any given project.)

Getting Started with TurboGears

TurboGears makes extensive use of a new Python package
management system called setuptools, which
allows you to easily install a package and all of its
prerequisites. In fact, without setuptools, it’s hard to
imagine a project like TurboGears ever being successful, as there
are nearly 20 dependencies in a standard TurboGears install.
However, using setuptools, you can install everything with a
single, simple command:

$ sudo python easy_install -f \
  http://www.turbogears.org/preview/download/index.html \
  --script-dir /usr/local/bin TurboGears

This command assumes that you already have Python and setuptools
installed. If you don’t have Python, you can download and
compile your own binary, or you can install the Python package from
your Linux distibution’s media or Web site. To install
setuptools, download and run the ez_setup

$ wget http://www.turbogears.org/preview/download/ez_setup.py
$ sudo python ez_setup.py

If your easy_install worked, you’re
all done. If not, the TurboGears site has a page listing some
common problems and solutions.

There’s just one more step in the TurboGears installation:
configuring a database server to hold your data. TurboGears
supports the popular MySQL and "i">Postgres databases, along with the easy to configure and
maintain SQLite. Every distribution should
have SQLite 3, but you may need to install
the Python SQLite drivers. Using "i">easy_install, you can get it with:

$ sudo easy_install pysqlite

For many developers, the hardest part of any project is getting
started, so TurboGears makes launching a new endeavor as easy as
possible. Just type tg-admin quickstart,
answer a couple of questions, and you’re ready to get

Let’s build a simple task tracking application called
“Action Flow.”

$ tg-admin quickstart
Enter project name: Action Flow
Enter package name [actionflow]:
Do you need identity (usernames/passwords) in this project? [no] 

The only thing you really need to know is the name of your
project. Enter that and TurboGears will try to create a reasonable
Python package name for you. If the generated package name works
for you, you can just accept the default. The third question
— the one about identity — takes a bit more thought. If
you’re building an application that requires users to login,
answer “yes.” For this sample project. the default,
“no,” is fine.

tg-admin quickstart creates a directory
named actionflow with all the files you need
to get started. TurboGears even comes with a built in Web server,
so all you need to do to view your first TurboGears page is
cd into your new directory and type:

$ python start-actionflow.py

This starts a Web server on port 8080, so if you browse to
http://localhost:8080/, you should see a welcome page with a few
instructions on how to get started.

Next, let’s look at the various parts that make up a
TurboGears application.

SUBHEADING: TurboGears Under the Hood

TurboGears applications are built using the "i">Model, View Controller (MVC) design pattern paradigm.
According to MVC, every application is divided into three

*The Model contains your data,
as well as the methods and logic necessary to maintain that

*The Controller processes user
actions, handling HTTP Requests and providing responses

*The View displays results.

In rough terms, TurboGears uses three pre-existing Python
libraries to handle each component. The Model is implemented with
SQLObject. The Controller is realized using
CherryPy, and the View is presented by

SQLObject provides an easy ActiveRecord
like interface to your relational database back end

At the center of everything is CherryPy, which listens for user
requests, and maps URLs directly to objects that handle the
requests. After all the server-side processing is complete,
CherryPy returns an HTTP response back to the user. Kid provides a
highly flexible and extensible XHTML templating engine.

Managing Tasks and Projects

To get a better understanding of how each of the MVC pieces
works, let’s build a first draft of a new, open source task
tracking application called Action Flow. Much of the theory behind
Action Flow comes from David Allin’s book “Getting
Things Done,” which recommends processing all incoming
requests into several buckets. “Tasks” (which Allin
calls “next actions”) can be completed in a single
sitting. “Projects” require multiple tasks to be
completed. And “contexts” represent the location or
resources that need to be present to complete a particular task.
Once your tasks are organized in this way, you can just look at the
context that matches your current circumstances and proceed.

The source code for this project is available at "http://code.google.com/p/actionflow/" class=
, and
there’s a discussion list at "http://groups.google.com/group/actionflow" class=

SUBHEADING: Creating the Action Flow Database and Model

TurboGears’s default data access layer is SQLObject, which
provides an easy way to access and save database rows via objects.
For instance, instantiating a new object creates a new row in the
database. Changing the attributes of an object updates the

So, you can create a new task like this:

a = Task(name= “Edit Project.kid”, 
  description=”We need a page that...”, context=1) 

And you can update that object to change its name like this:

a.name = “Create Project.kid”

In both cases, the database is automatically updated for

By default, TurboGears uses SQLite and no additional
configuration is required. However, if you use another database,
you should configure your database connection in "i">dev.cfg. This file contains good instructions on what to
modify, so even switching to MySQL, say, is painless.

Modifying the Model

The standard way of working with the TurboGears model and
SQLObject is to edit the model.py file,
create a set of classes that reflect the structure of each table,
and then use the tg-admin command to
generate the database schema automatically. You can easily modify
model.py by hand, but at the very start of a
project, it may be easier to use a TurboGears tool to visualize the

If you type tg-admin toolbox from the
root directory of your application, a set of TurboGears
applications designed to make TurboGears development easier will
pop up. For now we’re going to look at the "i">Model Designer, a Web-based tool used to define your
tables, columns, and interrelations. Model Designer is pictured in
Figure Two.

In the figure, the “tables” for task, project,
context, and task and project notes are being defined. Each table
has a number of columns, and the type of each column is defined
with a SQLObject column type object and a couple of attributes.
There’s a column type for just about any database field you
might need, and most of them are pretty self-explanatory.
(SQLObject’s online documentation isn’t perfect, but
you can find definitions of all the column types and all of the
configuration attributes at class="story_link">http://www.sqlobject.org.) However, there
are three “column types” that represent relationships
between tables that require a bit of explanation.

Tables can be related one-to-one, one-to-many, and many-to-many.
SQLObject let’s you define relationships in the same way that
you would define a standard column. For example, accessing a
MultipleJoin attribute gets you a list of
SQLObject s, while a "c">SingleJoin gets you a single "c">SQLObject. RelatedJoin actually
creates a joint table and “magically” creates new
methods that look like add "i">otherColumn and remove
to manage the contents of
that joint table. Accessing a RelatedJoin
attribute returns a list of SQLOBjects just like "c">MultipleJoin.

Often when generating Single and
MultipleJoin s, you’ll want to define
a ForeignKey column for the other end of the relationship, and
ModelDesigner makes this easy by allowing you to set it up at the
same time as the join column.

After you define each table, you can generate SQLObject code to
represent a row. (See Figure Three.) For
instance, the generated Task table has
SQLObject code that looks like Listing

The SQLObject
definition for a task

class Task(SQLObject):
name = StringCol(length=200,alternateID=True)
description = StringCol()
completed = BoolCol(default=”False”)
context = ForeignKey(“Context”)
project = ForeignKey(“Project”)
note =
created_on = DateTimeCol(default=datetime.now())
completed_on = DateTimeCol(default=None)

Notice that the created_on attribute has
a default value defined. If you want a default value of any kind,
including null, which is set using "c">default=None, you can define it as shown. In fact, you
can use any Python expression as the default. You might also deduce
that a DateTimeCol knows how to translate a
Python datetime object into something that
the database understands.

The rest of model.py looks pretty much
like the task class, and defines the rest of the tables.
Listing Two shows the entirety of the

The classes for the Action Flow

from sqlobject import *
from datetime import datetime
from turbogears.database import PackageHub
from turbogears.identity.soprovider import TG_User, TG_Group,

hub = PackageHub(“todone”)
__connection__ = hub

class Task(SQLObject):
name = StringCol(length=200,alternateID=True)
description = StringCol()
completed = BoolCol(default=”False”)
context = ForeignKey(“Context”)
project = ForeignKey(“Project”)
note =
created_on = DateTimeCol(default=datetime.now())
completed_on = DateTimeCol(default=None)

class Context(SQLObject):
task =
name = StringCol(length=100,alternateID=True)

class Project(SQLObject):
name = StringCol()
description = StringCol()
task =
note =
completed = BoolCol(default=”False”)
created_on = DateTimeCol(default=datetime.now())
completed_on = DateTimeCol(default=None)

class TaskNote(SQLObject):
note = StringCol()
task = ForeignKey(“Task”)
created_on = StringCol(default=datetime.now())
edited_on = StringCol(default=datetime.now())

class ProjectNote(SQLObject):
note = StringCol()
project = ForeignKey(“Project”)
created_on = DateTimeCol(default=datetime.now())
edited_on = DateTimeCol(default=datetime.now())

After using the Model Designer to create the tables, you can use
the command tg-admin sql create to generate
your database tables.

URL Handling in CherryPy

Of course a few model objects don’t make a Web
application. You have to listen for requests and create responses.
As mentioned above, CherryPy acts as the TurboGears application

CherryPy handles requests using an “object
publishing” paradigm: CherryPy maps URLs to controller
objects. For instance, if you request
http://localhost:8080/project, CherryPy plumbs for a "c">project() method in the root controller and calls it to
respond to the incoming request. If project
is instead a class with its own methods, then URLs that include
project route to its methods. For example,
project.list() is called to process


Here, the Action Flow application responds to several different
URL’s to list tasks in a variety of ways, such as by project,
by context, or by creation date. The snippet of code in
Listing Three surfaces three methods to
answer corresponding URLs.

The "i">Controller can handle many different requests, one per
exposed method

class Root(controllers.RootController):

def index(self):
return dict()

def project(self):
return dict(projects=Project.select(Project.q.completed ==

def task(self):
return dict(tasks=Task.select(Task.q.completed == False))

Only those methods with an @expose
decorator are mapped to URLs, so you can create non-published
methods just by omitting @expose. (Since
decorators are a feature new to Python 2.4, it’s worth
mentioning that a decorator is just a special function which takes
the decorated function and modifies it a bit before returning it.)
The @expose decorator also defines which
template should be called to render the final output. You can pass
in the template name either as the first positional parameter, or
as a named parameter.

Creating a Template to List Open Projects

Now that you know how templates get called, let’s take a
deeper look at how to create pages with Kid. Kid template files are
standard XHTML files with a few special
processing directives — useful because you can preview Kid
template files in Firefox without rendering through the server.
Listing Four shows the template.
Figure Four shows the template rendered in a
Web page.

A template to show all tasks by

<html xmlns=”http://www.w3.org/1999/xhtml”
<meta content=”text/html; charset=utf-8”
<title>Task Wiki</title>
<div py:for=”project in projects”>
<li py:for=”task in project.task”

Kid directives work just like their pure Python equivalents, so
the py:for loops over each project in the
projects list (which comes from the dictionary returned by the
controller). Rather than rely on indentation to determine the scope
of the loop, however, py:for returns just
loops over that element (including all sub-elements). In addition
to py:for, Kid also provides "c">py:if, py:def (for creating
reusable named template functions) and "c">py:match for doing simple XML tranformations.

When you put it all together it’s pretty powerful stuff.
In fact, the template of Listing Four pulls
in the header, sidebar, and footer automatically from the
master.kid file with a simple "c">py:extends directive up in the header. You can use Kid
to create custom tag libraries, and do all kinds of cool tricks
with page composition. But perhaps the best thing about Kid is that
the template itself must be valid XHTML, so the output is always

Widgets, Forms, and Ajax

TurboGears also provides a “widgets” package, a
flexible, extensible way to create re-usable page elements that
have complex Javascript, CSS,, and HTML.

One common use for widgets is form generation, including the
automatic display of error messages when the submitted input fails
validation. With a simple Python class that lists the form elements
and the vaildators for each element, you get a full fledged form
that can be easily reused in any template.

In Action Flow, the code to define the task form looks like
Listing Five.

A form to capture

class TaskFormFields(WidgetsList):

name = TextField(validator=validators.NotEmpty)
descripton = TextArea()
context = AutoCompleteField(search_controller =
search_param = “search”,
result_name = “contexts”)

project = AutoCompleteField(search_controller =
search_param = “search”,
result_name = “projects”)
completed = CheckBox(validator = validators.Bool)


The form object generated by the "c">TableForm widget knows how to render itself to an XHTML
table, how to pull down validation errors, and display the proper
messages. The only code needed to display all of this in a template
is this one-liner in form.kid:

${form(value=values, action=action)}

Of course, sometimes you want to customize each of the various
form elements or take control of every element of the form, and
TurboGears widgets are designed to make all of that as easy as
possible. Most of the time, customizing a form element is as simple
as overriding an attribute. And when you need to do more than that,
you can subclass a widget and add whatever attributes/behaviors you

JavaScript and TurboGears

Many frameworks try to insulate you from JavaScript as much as
possible. Rails and the Google Web Toolkit
even go so far as to create JavaScript generators in other
languages, so you can write JavaScript code in "i">Java or Ruby. But, with the right tools, it’s a
lot easier to just write your JavaScript in JavaScript– and it is
one hell of a lot easier to debug!

TurboGears’s philosophy is not to shy away from
JavaScript. Instead, TurboGear aims to make writing JavaScript
application features as easy as possible.

TurboGears includes the MochiKit
Javascript library as a core part of it’s package, and
provides other JavaScript application helpers, like easy to use
support for turning Python objects into serialized Javascript
objects. While you don’t have to use them, Ajax and
Javascript are a core part of the framework.

MochiKit’s slogan is “making JavaScript suck
less” and it provides a highly tested, well documented, cross
browser suite of tools that “just work.” Not only does
MochiKit make it easier to write cross-browser JavaScript, it makes
common tasks a lot nicer.


The TurboGears framework provides huge conveniences for the web
developer. There’s lots more to see, TurboGears even includes
the MochiKit JavaScript library as a first
class citizen in the framework, and has included Ajax oriented
functionality, like automatically generated JSON output, from
it’s very first release.

While nobody can predict the future, it seems pretty safe to say
that TurboGears 1.0 is just the beginning.

TurboGears already includes experimental support for SQLAlchemy,
the latest and greatest Object Relational Mapper. The current
support includes a layer called Active Mapper that allows for easy
database access just like what you currently find in Rails
ActiveRecors or SQLObject, but this layer will not preclude you
from using the full power of the Data Mapper pattern that can map
arbitrary SQL Queries to objects. In some future version of
TurboGears, SQLAlchemy will become the default install.

The next version will have significant improvements in
it’s Controller layer. Robert Brewer has done a lot of work
to make CherryPy 3.0 much cooler. He has benchmarks showing 100%
performance increases, improved flexibility, full HTTP 1.1 support,
along with much deeper support for the emerging WSGI (Web Server
Gateway Interface) standard. WSGI compatibility isn’t
something most web developers deal with every day, but it means
future TurboGears applications will have easy access to things like
high performance caching and session support.

At the View level the Markup project offers a very interesting
picture of the future. It’s already available to use with
TurboGears as a View plugin alternative to Kid. And it’s
built on top of the Kid syntax, which means that your Kid templates
will just work in Markup with very little modification. But Markup
offers significant performance improvements, greater flexibility in
how includes are done, better error reporting, the ability to
handle importing invalid HTML gracefully, and other productivity
enhancing features.

We’ll also have more and better Widgets, and other
improvements to the core framework. And none of this stuff is
Vaporware, it’s either an existing project with real users,
or available in subversion in some form.

You can reach Mark Ramm at "http://www.compoundthinking.com/blog" class=

Comments are closed.