Database-configured Theming in Pylons

Posted on January 6th, 2010 by raoul and tagged , , , , , .

Yesterday I looked at very simple theming in Pylons, and mentioned that I'd prefer loading the current theme from the database rather than the configuration file. So this evening I decided to see if I could achieve that.

Looking in environment.py, I noticed that SQLAlchemy and the models were being configured and initialised last in the load_environment method. I moved those two lines up to the top of that method, and changed "config" to "app_conf". Then I simply did a normal Session.query() to fetch my theme name out of the "variables" table in my database.

Now that I had my theme name, I constructed my theme directory using the path to the themes directory from my configuration file and the name of the theme from the database. Then I set up my static files and tempaltes directories using the new theme directory.

Lastly, I wanted to do something that Drupal, the CMS that powers this blog, does with it's theming system. Drupal has a set of fall-back templates so that if you don't provide (whether by mistake or by choice) all the templates a theme needs, the default Drupal templates are used. This was very easy to set up, because Mako's TemplateLookup class accepts a list of template paths. So all I did was add the normal Pylons template path to the list as well.

So now my file looks like this:

def load_environment(global_conf, app_conf):
    """
    Configure the Pylons environment via the ``pylons.config`` object
    """
    # Setup the SQLAlchemy database engine
    engine = engine_from_config(app_conf, 'sqlalchemy.')
    init_model(engine)

    # Pull out theme variable
    theme = Session.query(Variable).get(u'theme')
    if not theme:
        theme_name = u'default'
    else:
        theme_name = theme.value

    # Pylons paths
    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    theme_dir = os.path.join(app_conf[u'themes.directory'], theme_name)
    paths = dict(root=root,
                 controllers=os.path.join(root, 'controllers'),
                 static_files=os.path.join(theme_dir, 'public'),
                 templates=[os.path.join(theme_dir, 'templates'),
                            os.path.join(root, 'templates')])

As usual, any comments or suggestions are welcome