Search code examples
pythonpyramidportingpylons

How to port /{controller}/{action}/{id} routes in Pylons to Pyramid


So I'm porting some old Py2/Pylons app, which has the routes defined as in https://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/pylons/examples.html section #3 which isn't possible in Pyramid - so how to deal?

I'm not familiar with neither Pylons nor Pyramid really, so if its obvious I'd still like a hint.

I have 8 controllers with ~2-5 actions each, where only some uses the {id}, I'm thinking I would need to decorate each action function in each controller with separate route_names, except for the ones which do not use any id:

@view_defaults(renderer='go.pt', route_name='go')
class GoView:
    def __init__(self, request):
        self.request = request

    @view_config(match_param="action=list")
    def list(self):
        return {'name': 'Go list'}

    @view_config(route_name='go_edit')
    def edit(self):
        return {'name': 'Go edit id: {}'.format(self.request.matchdict["id"])}

    config.add_route("go", "/go/{action}"). # deals with all non-id routes pr controller
    config.add_route("go_edit", "/go/edit/{id}") # one for each controller+action using id

However, this gets to be quite many routes I need to add, compared to Pylons code - is this kosher Pyramid style, or is there some better way? Is it in fact better to add specific routes for each action whether it uses ID or not, even though it generates more calls to config.add_route?


Solution

  • Pyramid on its own requires granular route definitions. You can write helpers for this like

    def add_action_routes(config, name, path=None):
        if path is None:
            path = name
        if not path.endswith('/'):
            path += '/'
        config.add_route(name, path)
        config.add_route(name + '_action', path + '{action}')
        config.add_route(name + '_id', path + '{action}/{id}')
    
    add_action_routes(config, 'go')
    

    You can then use the view_defaults and view_config as you see fit to hook up views to these routes. On the flip side you could make your own url generator which deals correctly with generating a url of the correct format.

    def make_action_url(request, name, action=None, id=None, **kw):
        if action is None:
            return request.route_url(name, **kw)
        if id is None:
            return request.route_url(name + '_action', action=action, **kw)
        return request.route_url(name + '_id', action=action, id=id, **kw)
    
    config.add_request_method(make_action_url, 'action_url')
    

    This will allow your code to use request.action_url(...) to generate urls without bothering too much with the route names.