Python Bottle.py 装饰器困惑
我有一个叫做“auth”的装饰器。
def auth(check_func=validate_login):
def decorator(view):
def wrapper(*args, **kwargs):
auth = check_func()
if auth:
return view(*args, **kwargs)
return bottle.redirect('/login.html')
return wrapper
return decorator
这个 auth
装饰器是这样使用的:
@get('/')
@view("someview")
@auth()
def handler():
#myhandlercode
所以这个 auth
装饰器会调用 view
函数,这个函数在 bottle.py 中渲染我的模板。但现在我想返回 JSON,而不是渲染一个 view
。我需要对 auth
装饰器的代码做什么修改才能实现这个?我有点困惑,不知道怎么从 auth 代码中调用处理器,而不是 view
。
编辑 1:Bottle 允许你返回字典,它会直接把字典转换成 JSON。而我根本不想使用 view
,我只想从我的处理器返回 JSON 给用户。那么我是不是应该直接去掉 @view 装饰器?在 auth 装饰器中我应该调用什么呢?
3 个回答
你是从你的视图中返回Json(其实就是一个Python字典),对吧?在这种情况下,你不需要对装饰器做任何修改。视图返回的内容并不会直接发送到用户的浏览器,而是先经过Bottle框架的处理,然后再返回给用户。当你从视图返回一个字典时,它会被当作Json来处理;而如果返回的是一个模板字符串,那就会被当作Html来处理。
我觉得把认证和JSON输出搞在一起是不太合适的。
这里有个用普通Python的装饰器的例子:
def validate():
return True
def auth(valid=validate):
def _auth(f):
def _auth_wrap():
if not valid():
raise Exception('redirect')
return f()
return _auth_wrap
return _auth
def view(tmpl):
def _view(f):
def _view_wrap():
return tmpl.format(f())
return _view_wrap
return _view
@view('Hello, {0}')
@auth()
def handler():
return 'World'
handler
# outputs: __main__._view_wrap
handler()
# outputs: 'Hello, World'
还有这一行:
return tmpl.format(f())
这个f
函数是__main__._auth_wrap
,它在调用验证函数并返回执行的处理程序。
所以,处理JSON输出的方式应该和上面提到的tmpl.format
不一样,比如可以调用一个单独的方法并传递所需的信息,或者把它放进视图装饰器里,这样做会更合适。
为了更好地回答最后的问题,如果你想根据请求动态决定是否输出JSON,而_view_wrap
中调用json.dumps
来处理f()
。
如果你想让一个函数总是输出JSON,那就删除视图装饰器,创建一个类似于上面视图装饰器的JSON装饰器,这样它会return json.dumps(f())
。
这里的主要观点是让认证保持它的本职工作。
Bottle的路由装饰器可以在不影响自动生成JSON功能的情况下,给你添加装饰器。
@get('/', apply=[auth])
def handler():
...
如果你不想要某个视图,只需要去掉你的@view
装饰器,Bottle会很聪明地处理字典,把它转换成JSON格式的回答。