November 7, 2014

Flask路由使用装饰器的问题

需要实现验证用户登录的功能,考虑用装饰器实现:

def check_permission(func):
    def _check_permission(**args):
        #do check...
        return func(**args)
    return _check_permission

@app.route('/routea')
@check_permission
def a():
    pass

@app.route('/routeb')
@check_permission
def b():
    pass

当@check_permission只有一个时可以正常使用,但是超过一个就会报错:

AssertionError: View function mapping is overwriting an existing endpoint function: _check_permission

这样的错误是因为Flask在注册路由的时候使用了函数的名字,这个例子中是a和b,使用装饰器后a、b两个函数的名字都变成了_check_permission,造成冲突,提示overwriting。解决方法是加上@wraps():

from functools import wraps
def check_permission(func):
    @wraps(func)
    def _check_permission(**args):
        #do check...
        return func(**args)
    return _check_permission

@app.route('/routea')
@check_permission
def a():
    pass

@app.route('/routeb')
@check_permission
def b():
    pass

Python自带辅助库functools中的@wraps装饰器能够改变函数的__name__等,解决问题。具体原理参考下面:

http://coolshell.cn/articles/11265.html
http://stackoverflow.com/questions/19261833/what-is-an-endpoint-in-flask

补充:
完事之后才发现官方文档已经介绍过这个方法了,事实证明我是对的……

http://docs.jinkan.org/docs/flask/patterns/viewdecorators.html