Database-configured Theming in Pylons

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:

  1. def load_environment(global_conf, app_conf):
  2. """
  3. Configure the Pylons environment via the ``pylons.config`` object
  4. """
  5. # Setup the SQLAlchemy database engine
  6. engine = engine_from_config(app_conf, 'sqlalchemy.')
  7. init_model(engine)
  8.  
  9. # Pull out theme variable
  10. theme = Session.query(Variable).get(u'theme')
  11. if not theme:
  12. theme_name = u'default'
  13. else:
  14. theme_name = theme.value
  15.  
  16. # Pylons paths
  17. root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  18. theme_dir = os.path.join(app_conf[u'themes.directory'], theme_name)
  19. paths = dict(root=root,
  20. controllers=os.path.join(root, 'controllers'),
  21. static_files=os.path.join(theme_dir, 'public'),
  22. templates=[os.path.join(theme_dir, 'templates'),
  23. os.path.join(root, 'templates')])

As usual, any comments or suggestions are welcome