Search code examples
pythonjsonpython-3.xpyramid

Pyramid: generate json views from list


How to generate json views from a list of strings with Pyramid?

With the following attempt only the view of the last element of the list is generated; jkl_json in this case, the others produce 404 Not Found.

names = ['abc', 'def', 'ghi', 'jkl']
for nm in names:
    @view_config(route_name='{}_json'.format(nm),
                 renderer='json',)
    def names_json(request):
        nm_cls = globals()[nm.title()]
        ...

This does actually work with html views; but not with json views.


Solution

  • This happens because Pyramid uses the Venusian library for decorators; they attach information to functions instead of registering the view instantly. This information is later processed by config.scan, and only then is the route actually registered. In your code you're replacing the names_json function with another function by the same name on each loop. Since only last of them is visible in the module, with only the last view_config data attached to it, this is what Venusian picks up when scanning.


    You should instead apply the decorators to exactly one function. If you remember that

     @view_config(route_name='foo')
     def bar(request):
         return Response()
    

    is just syntactic sugar for

     def bar(request):
         return Response()
    
     bar = view_config(route_name='foo')
    

    you can do

    def names_json(request):
        ...
    
    names = ['abc', 'def', 'ghi', 'jkl']
    for nm in names:
        names_json = view_config(route_name='{}_json'.format(nm),
                 renderer='json')(names_json)
    

    On the other hand, if the paths are like this, perhaps you can just use a single route for all of them:

    config.add_route('names', '/foo/{name:abc|def|ghi|jkl}.json')
    

    where the route would match any of /foo/abc.json, /foo/def.json, /foo/ghi.json or /foo/jkl.json, and the name would be available as request.matchdict['name'] within the view.