Table Of Contents

Previous topic

Downloading and Installing TurboGears

Next topic

20 Minute Wiki Page 2

The 20 Minutes Wiki

This tutorial is also available as a screencast. The video moves quite quickly to demo TurboGears and hold your interest, but a number of new users have reported having difficulty following certain parts. This tutorial initially was a direct translation of the video, but has been rewritten to be a gentler introduction.

Note

This tutorial is for TurboGears 1.5 which is based on CherryPy. If you are new to TurboGears, we recommend using the latest version in the TurboGears 2 branch which is based on Pylons. Have a look at the TurboGears homepage to find the documentation and tutorials for the latest version of TurboGears.

If you’re having trouble with this tutorial, you can ask for help on the TurboGears discussion list. We’re a friendly bunch and depending what time of day you post, you’ll get your answer in a few minutes to a few hours. If you search the mailing list or the web in general, you’ll probably get your answer even faster.

For further troubleshooting, here’s the final code for this tutorial. If you do wind up needing to use it, please let us know so we can clarify that portion of the tutorial.

Setting Up

To go through this tutorial, you’ll want:

  1. TurboGears 1.5 or higher.

  2. A database for storing the wiki’s pages. If you don’t have one, you can use the SQLite database that comes packaged with Python 2.5 and higher.

  3. SQLAlchemy 0.6 or higher for dealing with the database. Install it with:

    easy_install docutils
    
  4. Docutils 0.6 or higher, which is used for the wiki’s formatting. Docutils is not a required part of TurboGears but is needed for this tutorial. Install it with:

    easy_install docutils
    
  5. A web browser

  6. Your favorite editor

  7. Two command line windows (you only need one, but two is nicer.)

  8. optional If you’re not aware of it, you may also find the ipython shell to be helpful. It supports attribute tab completion for many objects (which can help you find the method you’re searching for) and can display contextual help if you append a question mark onto the end of an object or method. You can do the same in the standard shell with the dir() and help() functions, but ipython is more convenient. ipython has a number of other convenient features (like dropping into the debugger on error), check the ipython docs or online help.

This tutorial doesn’t cover Python at all. Check the Python homepage page for more coverage of Python.

The Quickstart

TurboGears has a command line tool named tg-admin, which provides a suite of tools for working with TurboGears projects. A few will be touched upon in this tutorial, check the tg-admin reference for a full listing. The first tool you’ll need is quickstart, which initializes a TurboGears project. Go to one of your command line windows and run the following command:

tg-admin quickstart

You’ll be prompted for the name of the project (this is the pretty name that human beings would appreciate), and the name of the package (this is the less-pretty name that Python will like). For the identity prompt, answer ‘no’, since we’ll keep this wiki fairly simple, but when you need users/passwords in a future project, you’ll want to look up the identity management tutorial. Here’s what our choices for this tutorial look like:

Enter project name: Wiki 20
Enter package name [wiki20]: wiki20
Do you need Identity (usernames/passwords) in this project? [no] no
...output...

This creates a few files in a directory tree just below your current directory. Let’s go in there and you can take a look around:

cd Wiki-20

Use this newly created project directory as the base directory for all commands issued in this tutorial.

Now Serving: Number 1

You may have spotted a file called start-wiki20.py. This script starts the built-in web server. Let’s run it! Go to your second command line window and run:

python start-wiki20.py

You should get some log messages on your console, one of them should say INFO TurboGears has been started.

Point your browser at http://localhost:8080/, and you’ll see a nice little welcome page with the current date and time. (If you’re on a Mac and have Bonjour bookmarks turned on in Safari, you’ll see your new server show up there!)

That was easy!

Easy indeed. You have a working project! If you take a look at the code that quickstart created, you’ll see that there isn’t much involved in getting up and running. In particular, you’ll want to check out the two files directly involved in displaying this welcome page:

  • wiki20/controllers.py has the code that’s generating the welcome page. CherryPy (TurboGears’ controller/app server) works using object publishing. You write methods and @expose() them to the web.

    TurboGears adds template processing to the default CherryPy decorator, you just specify your template, return a dictionary, and TG takes care of the rest. This has a number of advantages over returning some sort of string object, which we’ll get to later in this tutorial.

  • wiki20/templates/welcome.html is the template you view on the welcome screen. TurboGears 1.5 uses Genshi templates by default. Did you notice that it’s standard XHTML with some simple namespaced attributes? Very designer-friendly. You can even open it directly in your browser!

Let’s make a wiki!

If you’re not familiar with a wiki, you might want to check out the Wikipedia entry. The whole idea is that it’s an easily-editable collaborative web content system that makes it trivial to link to pages and create new pages.

TurboGears follows the Model-View-Controller paradigm, as do most modern web frameworks. Genshi templates are your view, your CherryPy classes are your controllers and basically any object can be your model. In practice, since we’re in a database-driven world, your model will be based on a relational database. SQLAlchemy is powerful and makes working with databases easy.

TurboGears quickstart gave us a wiki20/model.py module with enough in it to start creating model classes. Since a wiki is basically a linked collection of pages, we’ll define a Page class as the name of our model. Here’s what it looks like, you’ll want to insert it into your wiki20/model.py file under # your model classes:

class Page(Base):
    __tablename__ = 'page'

    pagename = Column(Unicode(30), primary_key=True)
    data = Column(Unicode)

    def __init__(self, pagename, data=None):
        self.pagename = pagename
        self.data = data

    def __repr__(self):
        return "<Page(%r)>" % (self.pagename)

There are different options for mapping your model classes to database tables. You can do it manually, by first defining the tables, then the classes, and then explicitely applying the mappings. Or, as we are doing here, you can use the “declarative” method provided by SQLAlchemy. Here, you simply let your model classes inherit from a base class provided by SQLAlchemy that you need to set up as follows at the top of your wiki20/model.py file, below the other imports:

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base(metadata=metadata, mapper=mapper)

Alternatively, we could have also used Elixir as a declarative layer on top of SQLAlchemy.

For some extra convenience, we use a “session-aware” mapper instead of the “bare-bones” SQLAlchemy mapper for this tutorial. The only thing we need to do is to make sure we execute:

from turbogears.database import session_mapper as mapper

instead of:

from sqlalchemy.orm import mapper

in the import section of our wiki20/model.py file.

Most TurboGears developers and users prefer to work with objects (and not SQL) as much as possible. SQLAlchemy does support creating objects based on the database definition, but if you work the other way and create the database definition based on the objects, your database information lives in one place and your table-declarations are database independent.

For the pagename, we specified primary_key=True, which will guarantee that the column is unique and allow us to select a Page from our model using its pagename rather than an arbitrary surrogate key. Of course, surrogate keys also have their advantages and you can easily create such surrogate keys with SQLAlchemy. You would still want to set unique=True for the pagename.

Continue on to page 2