Custom dispatcher in CherryPy

Despite my previous success in using Routes with CherryPy (partially at least… I never could get URL generation to work properly), I’ve been looking into nice, easy, clean ways to use the default method as a custom dispatcher for a given controller.

For example, the app I’m currently working on is a simple ticket system to handle support requests from clients. I want to be able to access tickets in a semi-RESTful manner:

/ticket/[ticket id]/[action]

This might have been made easier on myself if I’d gone for the URL structure below as all of CherryPy’s methods now allow for positional parameters.

/ticket/[action]/[ticket id]

However, that structure doesn’t work logically in my head and I’m a stickler for detail.

Having used irclib for a while now it dawned on me that I could simplify my default methods in CherryPy using a very similar dispatch method.

My default method for the ticket controller is now as follows:

@expose()
def default(self, id=None, action="view", *args, **kw):
    try:
        ticket = model.Ticket.get(int(id))
    except SQLObjectNotFound:
        raise NotFound
    except ValueError:
        raise NotFound

    handler = "on_%s" % action
    if hasattr(self, handler):
        return getattr(self, handler)(ticket, *args, **kw)
    else:
        raise NotFound

This lets you dynamically map an action to a method and have room to breathe without going through a big list of if/elif clauses to find the right method.

The mapped methods don’t even have to be decorated with @expose so there’s no chance of having two URL’s with the same purpose.

The default action is “view” so let me show you what my on_view method looks like:

def on_view(self, ticket, *args, **kw):
    template = ".templates.client_ticket_view"
    if "view_tickets" in identity.current.permissions:
        return dict(tg_template=template, ticket=ticket)
    else:
        raise identity.IdentityFailure("You do not have permission...")

Returning tg_template in the dict sets the template for that method, so when it gets called you can change the template… you can actually do this on any exposed method and override the template programatically.

All that is left to do is create the rest of your action methods for that controller and you have your dispatcher working to create nice URL’s for you.