Latest Version: 0.9.6.2
  Dashboard > Pylons Cookbook > ... > Controllers > Alternative controller searching method
  Pylons Cookbook Log In | Sign Up   View a printable version of the current page.  
  Alternative controller searching method
Added by Dan Korostelev, last edited by Dan Korostelev on Aug 08, 2007
Labels: 

Alternative controller searching method

Warning

This article is in DRAFT status. It needs rewording and style improvement.
Documentation masters, please help!

Be Careful

This article is for advanced users!

Be Careful

This article is for Pylons 0.9.6!
In older versions the configuration layout is different, but it is still possible to implement this, I think.

Intro

Sometimes the default controller finding method is not very handy. For example if you want controllers to be loaded from other package, or you are implementing some kind of plugin system where plugins can add their controllers to the routing.

Here's some advices on how can you implement it.

First, Routes define and use a controller_scan method, that scans modules in a specified directory by default, but we can override it. Then, when Routes match a route to a controller name, PylonsBaseWSGIApp's find_controller method is used to get a class from the controller name. We can subclass the the PylonsBaseWSGIApp and override that method.

For example, we want to have a dictionary of controller keys and classes, like this:

1
2
3
4
5
from otherpackage.controllers import hello
from mypackage.controllers import blog
from mypackage.controllers.page import PageController

controllers = {'hello': hello.Controller, 'blog':  blog.BlogController, 'page': PageController}

Implementation

Now we need to setup our application to search controllers using this variable. Create a test application for this tutorial and a "Hello, world!" controller:

1
2
3
$ paster create -t pylons testapp
$ cd testapp/
$ paster controller hello

Now go to testapp/testapp/config directory and open the environment.py file. The list of controllers is a part of application environment so it's sane to create it here. And for global use, we'll save it in the config object. So in the load_environment function, just after this line:

1
2
config.init_app(global_conf, app_conf, package='testapp',
                template_engine='mako', paths=paths)

add something like the following:

1
2
3
4
5
6
7
from testapp.controllers.error import ErrorController
from testapp.controllers.template import TemplateController
from testapp.controllers.hello import HelloController

config['pylons.controllers'] = {'error': ErrorController,
                                'hello': HelloController,
                                'template': TemplateController}

So, now we have a mapping of controller names to actual controller classes. We will make Pylons use it instead of directory lookup method provided by default.

Open the routing.py file and at the top of make_map function, locate this call:

1
2
map = Mapper(directory=config['pylons.paths']['controllers'],
             always_scan=config['debug'])

This means that the Mapper will try to get the available controller list by listing files in our project's controllers directory. But we can specify own function to get the available controller list. Change the line above to this:

1
2
map = Mapper(controller_scan=lambda: config['pylons.controllers'].keys(),
             always_scan=config['debug'])

Okay, now Routes will use our dictionary keys for matching controller names. But still, Pylons will load controllers using the old method (the controller module <package_name>.controllers.<controller_name> is loaded and the class with name <controller_name>.title()+'Controller' is loaded from it). To change this, we need to override the find_controller method in Pylon's base WSGI application.

Open the middleware.py file and find these lines:

1
2
# The Pylons WSGI app
app = PylonsApp()

Add the following ABOVE:

1
2
3
4
5
from pylons.wsgiapp import PylonsBaseWSGIApp

class MyBaseWSGIApp(PylonsBaseWSGIApp):
    def find_controller(self, controller):
        return config['pylons.controllers'][controller]

Now, change the the app = PylonsApp() line, mentioned above to this:

1
2
# The Pylons WSGI app using custom controller find method
app = PylonsApp(base_wsgi_app=MyBaseWSGIApp)

That's all. Now the default controller finding method is overriden and Pylons will use the mapping you specified in the config['pylons.controllers'], you can map URL schemas against its keys and their values will be used as controller classes.

Using this technique, you can load controller classes from other packages and/or implement a configurable controller mapping system.

Hope it helps...

Site running on a free Atlassian Confluence Open Source Project License granted to Pylons. Evaluate Confluence today.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.3.3 Build:#645 Feb 13, 2007) - Bug/feature request - Contact Administrators
Top