使用视图映射器将查询参数作为关键字参数传递

Pyramid 支持“视图映射器”的概念。见 Using a View Mapper 有关视图映射器的常规信息。您可以使用视图映射器来支持另一种方便调用约定,在该约定中,您允许视图可调用文件命名从request.params字典中获取的额外必需和可选参数。例如,不是:

1@view_config()
2def aview(request):
3    name = request.params['name']
4    value = request.params.get('value', 'default')
5    ...

使用特殊的视图映射器,可以将其定义为:

@view_config(mapper=MapplyViewMapper)
def aview(request, name, value='default'):
    ...

The below code implements the MapplyViewMapper . It works as a mapper for function view callables and method view callables:

  1import inspect
  2import sys
  3
  4from pyramid.view import view_config
  5from pyramid.response import Response
  6from pyramid.config import Configurator
  7from waitress import serve
  8
  9PY3 = sys.version_info[0] == 3
 10
 11if PY3:
 12    im_func = '__func__'
 13    func_defaults = '__defaults__'
 14    func_code = '__code__'
 15else:
 16    im_func = 'im_func'
 17    func_defaults = 'func_defaults'
 18    func_code = 'func_code'
 19
 20def mapply(ob, positional, keyword):
 21
 22    f = ob
 23    im = False
 24
 25    if hasattr(f, im_func):
 26        im = True
 27
 28    if im:
 29        f = getattr(f, im_func)
 30        c = getattr(f, func_code)
 31        defaults = getattr(f, func_defaults)
 32        names = c.co_varnames[1:c.co_argcount]
 33    else:
 34        defaults = getattr(f, func_defaults)
 35        c = getattr(f, func_code)
 36        names = c.co_varnames[:c.co_argcount]
 37
 38    nargs = len(names)
 39    args = []
 40    if positional:
 41        positional = list(positional)
 42        if len(positional) > nargs:
 43            raise TypeError('too many arguments')
 44        args = positional
 45
 46    get = keyword.get
 47    nrequired = len(names) - (len(defaults or ()))
 48    for index in range(len(args), len(names)):
 49        name = names[index]
 50        v = get(name, args)
 51        if v is args:
 52            if index < nrequired:
 53                raise TypeError('argument %s was omitted' % name)
 54            else:
 55                v = defaults[index-nrequired]
 56        args.append(v)
 57
 58    args = tuple(args)
 59    return ob(*args)
 60
 61
 62class MapplyViewMapper(object):
 63    def __init__(self, **kw):
 64        self.attr = kw.get('attr')
 65
 66    def __call__(self, view):
 67        def wrapper(context, request):
 68            keywords = dict(request.params.items())
 69            if inspect.isclass(view):
 70                inst = view(request)
 71                meth = getattr(inst, self.attr)
 72                response = mapply(meth, (), keywords)
 73            else:
 74                # it's a function
 75                response = mapply(view, (request,), keywords)
 76            return response
 77
 78        return wrapper
 79
 80@view_config(name='function', mapper=MapplyViewMapper)
 81def view_function(request, one, two=False):
 82    return Response('one: %s, two: %s' % (one, two))
 83
 84class ViewClass(object):
 85    __view_mapper__ = MapplyViewMapper
 86    def __init__(self, request):
 87        self.request = request
 88
 89    @view_config(name='method')
 90    def view_method(self, one, two=False):
 91        return Response('one: %s, two: %s' % (one, two))
 92
 93if __name__ == '__main__':
 94    config = Configurator()
 95    config.scan('.')
 96    app = config.make_wsgi_app()
 97    serve(app)
 98
 99# http://localhost:8080/function --> (exception; no "one" arg supplied)
100
101# http://localhost:8080/function?one=1 --> one: '1', two: False
102
103# http://localhost:8080/function?one=1&two=2 --> one: '1', two: '2'
104
105# http://localhost:8080/method --> (exception; no "one" arg supplied)
106
107# http://localhost:8080/method?one=1 --> one: '1', two: False
108
109# http://localhost:8080/method?one=1&two=2 --> one: '1', two: '2'