Approximately Me

Using Routes for Configuring Controllers

Aug. 16, 2008

In all examples I have seen of Pylons controllers on the Web the paths to the templates being rendered have been hard-coded in the controllers. In a case where you would have different views of the same data, this could lead to people creating one controller for each template rendering the view, with all the controllers looking the same except for the final return statement. This is, of course, wasteful, and it violates the DRY principle. Could it be done differently?

In WebWork and Struts 2 the template paths and result types are configured externally (in XML), making the controllers completely unaware of what kind of view of the controller data is returned to the client. And if the controllers are mapped up as beans in a dependeny injecting container as well, they can be made pretty reusable by extracting all specificness into appropriate configuration files. But these frameworks are Java frameworks, and I am interested in Pylons controllers here.

Pylons does not include a dependency injection framework, but whatever is defined in the routings it is available to the controllers through the environ['pylons.routes_dict']. So the route mapping is a possible subject for configuring controllers. Each controller should not need to be aware of the just mentioned access to route information, so the base controller, or another supercontroller, should abstract away the source of the configuration. A simplistic example:

In config/routing.py:

map.connect('list_exploded', '/list/exploded', controller='list', action='all',
            template='exploded.tmpl')

In lib/base.py:

def __call__(self, environ, start_response):
    self.template = environ['pylons.routes_dict'].get('template')

In controllers/list.py:

class ListController(BaseController):
    def all(self):
        # ....
        return render(self.template)

The routing maps a generic «list all» action to an exploded view of all elements of something. The base controller just makes the value from the routes mapping available to the current controller, and the eventual action does not care about which template it is rendering, as long as a template path has been mapped up. A different mapping of the same controller could provide a different template path.

The solution can, of course, be made much more powerful, including more template paths for more actions, redirect paths, (semi-)constants, and similar, or just a dictionary of properties required by the controllers for them to work properly. A more advanced solution could even include mapping of result types, making the Pylons controllers completely unaware of what they return at any point. Imagination is the limit, but I would possibly find convenient a dependency injection framework with Pylons.

I would like to see more examples of Pylons controllers not hard-coding view references in the controllers, and I have outlined one possible way for doing this. I have not tried any such solution yet myself, but I probably will.