Using TurboGears with SQLite

TurboGears is a "full stack" web application framework for Python developers. The TurboGears web site has a "20-minute" tutorial for creating a wiki using this framework. This page describes some additional details that I had to deal with to run through the tutorial on my computer.

These notes relate to an installation on a PC running Windows XP.


1. Prerequisites

The "20 minute" tutorial does not include sorting out the tutorial's prerequisites:

  1. A Python installation (2.4 or later, as TurboGears uses Python "decorators").

  2. docutils 0.3.9, which is used for formatting. You could get away with not having docutils, but it's not as much fun. easy_install docutils should get you what you need.

  3. A web browser
  4. Your favorite editor
  5. Two command line windows (you only need one, but two is nicer.)
  6. A database. If you don't have one, your best bet is sqlite 3.2+ with pysqlite 2.0+.

and, of course, an installation of TurboGears.

2. SQLite database installation

The following steps should be sufficient to install SQLite and its Python interface so that the TurboGears tutorial can be run.

2.1. Installing the SQLite database software

Download the following files, linked from, into a temporary working directory:

Unzip the contents of these zip files into a directory that is on the path. (I have a development utilities directory for this purpose.)

2.2. Installing the PySqlite API wrapper

(See also the PySQLite wiki page at

3. Running the TurboGears tutorial

The tutorial can be found here:

Create a new directory for the tutorial, and make it the current directory before starting.

Editing the file dev.cfg to specify the database location, I use the following line:


where D:\Svn\Thirtover\WebBrick\Trunk\WebBrickConfig\SpikeCode\TurboGears\tryout is the directory from which I am running the tutorial.

Initially, after editing the dev.cfg file, I got a strange error cherrypy._cperror.WrongConfigValue: section: 'global', option: 'sqlobject.dburi', value: '"sqlite:///D|/Svn/Thirtover/WebBrick/Trunk/WebBrickConfig/SpikeCode/TurboGears/tryout/tryout/db/tryout.sqlite', which turned out to be caused by forgetting the closing quote on the line in the configuration file.

When creating the wiki front page in the database, note that there are two lines of input, one to open the interactive shell, and a second to actually create the database entry:

D:\Svn\Thirtover\WebBrick\Trunk\WebBrickConfig\SpikeCode\TurboGears\tryout>tg-admin shell
Python 2.4.1 (#65, Mar 30 2005, 09:13:57) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> Page(pagename="FrontPage", data="Welcome to my front page")
<Page 1 pagename='FrontPage' data="'Welcome to my fr...'">
>>> ^Z

Note that Page is a class defined in that is derived from SQLObject, and that creating an instance of this class causes a corresponding database entry to be created. Roughly: Class => Table, Instance => Row.

Having followed the instructions for adding the Edit page, the web server application must be restarted, or clicking the edit link results in the /edit page not being found, and a stack trace is displayed. (This is slightly surprising: I have found that CherryPy, the controller component here, is usually able to detect when controller source code has been changed, and force a reload of the web server. Indeed, when I followed the tutorial instructions and added the "Save" aqction, this is exactly what happened.)

When editing the Kid templates, be warned that HTML/XML style <!-- (stuff) -->  comments are not allowed, despite the fact that they are described as being valid XML. Worse, if such comments are included, horrendously obscure error messages can result. This may prove to be a weak point in the TurboGears framework: the advantage of separating presentation templates from controller logic is somewhat diluted if template syntax errors result in obscure errors from the Python code. Here's the offending error message: - - [2005/11/30 17:32:36] "GET /notfound?pagename=BooBoo HTTP/1.1" 500 2910
2005/11/30 17:45:21 HTTP INFO - GET /edit?pagename=FrontPage HTTP/1.1
2005-11-30 17:45:22,217 turbogears.view DEBUG Recompiling template for tryout.templates.edit
2005-11-30 17:45:22,227 turbogears.view DEBUG Applying template tryout.templates.edit
2005/11/30 17:45:22  INFO Traceback (most recent call last):
  File "c:\dev\python241\lib\site-packages\CherryPy-2.1.0-py2.4.egg\cherrypy\", line 271, in run
  File "c:\dev\python241\lib\site-packages\CherryPy-2.1.0-py2.4.egg\cherrypy\", line 502, in main
    body = page_handler(*args, **cherrypy.request.paramMap)
  File "c:\dev\python241\lib\site-packages\TurboGears-0.8a4-py2.4.egg\turbogears\", line 122, in newfunc
    return controllers._process_output(tg_format, output, html)
  File "c:\dev\python241\lib\site-packages\TurboGears-0.8a4-py2.4.egg\turbogears\", line 38, in _process_output
    output = view.render(output, tg_format, template=template)
  File "c:\dev\python241\lib\site-packages\TurboGears-0.8a4-py2.4.egg\turbogears\", line 99, in render
    return t.serialize(encoding="utf-8", output=format, fragment=fragment)
  File "c:\dev\python241\lib\site-packages\kid-0.7adev_r186-py2.4.egg\kid\", line 231, in serialize
    return serializer.serialize(self, encoding, fragment)
  File "c:\dev\python241\lib\site-packages\kid-0.7adev_r186-py2.4.egg\kid\", line 47, in serialize
    text = list(self.generate(stream, encoding, fragment))
  File "c:\dev\python241\lib\site-packages\kid-0.7adev_r186-py2.4.egg\kid\", line 301, in generate
    for ev, item in self.apply_filters(stream):
  File "c:\dev\python241\lib\site-packages\kid-0.7adev_r186-py2.4.egg\kid\", line 73, in balancing_filter
    for ev, item in stream:
  File "c:\dev\python241\lib\site-packages\kid-0.7adev_r186-py2.4.egg\kid\", line 179, in _coalesce
    for ev, item in stream:
  File "c:\dev\python241\lib\site-packages\kid-0.7adev_r186-py2.4.egg\kid\", line 21, in transform_filter
    for ev, item in apply_matches(stream, template, templates, apply_func):
  File "c:\dev\python241\lib\site-packages\kid-0.7adev_r186-py2.4.egg\kid\", line 31, in apply_matches
    item = stream.expand()
  File "c:\dev\python241\lib\site-packages\kid-0.7adev_r186-py2.4.egg\kid\", line 91, in expand
TypeError: append() argument 1 must be Element, not instance

(This problem, or something like it, appears to have been recently fixed in Kid: [I'll remove the above comment when the fix makes its way into a mainstream TurboGears distro.])

AJAX capability is provided by a javascript library MochiKit. The tutorial uses a format called JSON (Javascript Object Notation; a representation for structured data using Javascript syntax elements), so it is not strictly AJAX, but the ideas are similar. XML data requests are also supported by MochiKit. Note that the tutorial presents the Javascript samples in separate sections that must be used together: one cannot reload the page after entering each bit, but must add them all in before the result can be tested.

The asynchronous aspect of the callback is not immediately evident when running the tutorial code, as the result is provided immediately. Observe that function loadJSONDoc returns its result via a callback, which may occur after an arbitrary delay.

4. Debugging TurboGears templates

As noted above, templates are compiled to Python bytecodes, and can be difficult to debug. One feature that may be helpful is to define an environment variable: {{{set KID_OUTPUT_PY=1 }}} This causes the Python code for the template to be saved in the template directory (along with the compiled PYC file), and may be used to locate the source of template errors reported by the Python compile and run-tiume system.

A technique for including comments in Kid templates is to use an arbitrary tag along with a py:replace="''" attribute; e.g. {{{<c py:replace="">Here is my commentary text</c> }}} But note that the py:replace attribute must not be empty: a valid Python expression is required here, and an empty string seems to do the job.

5. The 7-line "Hello world" web server

import cherrypy
class HelloWorld:
    def index(self):
        return 'Hello World' = True
cherrypy.root = HelloWorld()

That's it!

Run this python program (with Python and TurboGears or CherryPy installed)) and you have a web server on port 8080. Of course, trivial programs to do trivial things aren't that big a deal, but what is impressive about CherryPy is that when you want to do something serious, the amount of code required increases rather gracefully. Roughly, initial growth is one class per directory, and one function per page.

6. Turbogears and AJAX

Shipped with TurboGears is a Javascript library called "MochiKit". This is a client-side (browser-side) programming framework that can be used to handle user interface events in the browser, often with additional HTTP requests back to the web server to fetch additional information. For the most part, MochiKit is independent of the TurboGears server-side software, and the two are not integrated in any special way.

At the time of writing, the current release of TurboGears (0.8a4) ships with version 1.0 of MochiKit, but the current version of MochiKit is version 1.1. Online documentation for MochiKit refers to version 1.1. One important difference between the versions is support for additional arguments to callback functions (handled using "curried" or "partially applied" functions).

The later version of MochiKit can be used with TurboGears 0.8a4 simply by virtue of downloading the latest MochiKit version, unzipping it into a temporary directory and copying file packed/MochiKit/MochiKit.js from there to directory python/Lib/site-packages/TurboGears-0.8a4-py2.4.egg/turbogears/js (where python is the directory where the Python language software has been installed).

7. TurboGears documentation

These are what I have found to be key documents for understanding and using TurboGears:

-- GrahamKlyne 2005-11-30 18:26:28

Creative Commons License
The content of this wiki is licensed under the Creative Commons Attribution-ShareAlike 2.0 England & Wales Licence.

OSS Watch is funded by the Joint Information Systems Committee (JISC) and is situated within the Research Technologies Service (RTS) of the University of Oxford.