Pages CMS (tgext.pages)


Pages is a simple CMS installable in any Turbogears 2 project. Pages supports multi level navigation and page templates done with Genshi. Pages can be used for tiny to big content websites and simple blogs.

This project is still alpha, and install isn't yet really beginner friendly.

0. Installing tgext.pages

1 - The first step is to install the project in your python path (it's recommended to have a virtualenv set up) by doing python develop (or pip install -e .)

2 - If you want to install pages without having an existing TG 2 project, the first step is to create a TG2 project. If you already have a project, skip this step. To do so, follow the instructions at

1. Installing pages models in your project

There are two ways to install pages. The manual way, and the paster script way:

Paster Script (easy)

This feature will only work with TG trunk, as it requires a feature not present in TG2.0.x

inside your tg application type: paster pages setup [my.ini] [-l language,language,language]

pages will not over-write if there is an existing pages instance installed. pages will not update your database unless you provide an ini file to do so. pages will create all Babel language files for you, defaulting to en,fr,ru,es, unless otherwise specified with the -l flag pages will not modify your controller, this is up to you, and is explained later in the document.

Manual (harder)

1 - Add these lines at the end of model/ in your project:

#set the metadata of the extension to our application's metadata
import tgext.pages.model as pages_model
pages_model.metadata = metadata
pages_model.DBSession = DBSession

#get the tables and mappers
from tgext.pages.model.pages import *

2 - Prepare i18n on your project:

<install Babel if you haven't>
python extract_messages
python init_catalog -l en # do this with all the languages you want
python compile_catalog

3 - bootstrap the default objects from tgext.pages in your add the following import:

from tgext.pages.websetup import bootstrap as pages_bootstrap

and somewhere inside your setup_app function a call to bootstrap:

print "Creating tgext.pages tables"

This will insert the default languages as well as the default templates, if you want to customize the values simply import directly the functions or write your own replacements

4 - launch paster setup-app development.ini (or the relevant .ini) in your project folder to create the pages tables

2. Mounting pages in your controller

First, import the pages controller in your python file (controllers/ if you want to install it at the root):

from tgext.pages.controllers import PagesController

You have two options to do so :

1) Mount it on the root, so all page, if not found in your controller logics will be redirected to CMS and finally to the error controller. To do so, change "class RootController(BaseController):" to "class RootController(BaseController, PagesController):"

  1. Add: pages = PagesController()

    to any controller in your project.

3) Changing your master template to include Menus and Languages

In order to get pages to appear in your package's menu, you have to provide a set of links that work with your pages controller. There are 3 steps to accomplish this:

1) Add a small python block at the top of your template which will pull in the proper pages objects for menus and languages: <?python

from pylons import request from tgext.pages.core import LangList, Menu, get_locale locale = get_locale() langurls = LangList().get_urls('/pages', request.path_info) menu_items = Menu().get_menuitems(locale=locale, pages_root='/pages/')

?> Don't forget to replace /pages with the root folder of your pages installation

  1. Add the menu items to the menu block in your master template::
    <li py:for="i, menuitem in enumerate(menu_items)">

    <a href="${menuitem['url']}" class="${('','active')[menuitem['url'].endswith(request.path_info)]}">${menuitem['name']}</a></li>

  2. Add in the language links which will only be active for urls that are in your pages controller::

    <div id="languages"> <py:for each ="lang, url in langurls.iteritems()" >

    <a href="$url"

    class="lang${('', ' active')[locale==lang]}" >$lang</a>

    </py:for> </div>


This application has been developed and tested with sqlite and Postgresql 8.2 so we cannot predict the full comportment of other database backends but mysql should be pretty safe bet as long as you are sure you use an unicode aware version.

Why unicode? Because our app stores all the language versions in the database. In our test application that we use for testing along our development cycle we use French, English, Spanish, and Russian. So obviously to be able to store those 4 languages in the same database you need a unicode aware server.