在Flask中,路由通过@app.route()装饰器来生成对应关系,此时如果我们再在这个装饰器的基础上再加装饰器,可能会出现如下的错误,这里对这个错误做一点解读,为什么会出现这种情况:
Traceback (most recent call last):
File "code.py", line 4, in <module>
app = Flask(__name__, template_foler='templates')
TypeError: __init__() got an unexpected keyword argument 'template_foler'
(fla) root@Andy963:/mnt/c/Users/lg/Desktop# python code.py
Traceback (most recent call last):
File "code.py", line 21, in <module>
@auth
File "/root/env/fla/lib/python3.6/site-packages/flask/app.py", line 1314, in decorator
self.add_url_rule(rule, endpoint, f, **options)
File "/root/env/fla/lib/python3.6/site-packages/flask/app.py", line 98, in wrapper_func
return f(self, *args, **kwargs)
File "/root/env/fla/lib/python3.6/site-packages/flask/app.py", line 1283, in add_url_rule
"existing endpoint function: %s" % endpoint
AssertionError: View function mapping is overwriting an existing endpoint function: inner
意思是endpoint重复了,endpoint在flask中是别名,类似于django中的name
我们先看下装饰器的一个特性,可以参考我的另一文章:http://www.jingang.ga/article/47/
def auth(func):
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
@auth
def login():
pass
@auth
def index():
pass
print(login.__name__)
print(index.__name__)
输出:
inner
inner
在没有使用functools的情况下,被装饰的函数的__name__都变成了inner.
我们再加上flask中的装饰器:
@app.route('/login')
@auth
def login():
pass
@app.route('/index')
@auth
def index():
pass
这样,传给@app.route()的函数名都是Inner,那我们看看router的源码:
def route(self, rule, **options):
"""Like :meth:`Flask.route` but for a blueprint. The endpoint for the
:func:`url_for` function is prefixed with the name of the blueprint.
"""
def decorator(f):
endpoint = options.pop("endpoint", f.__name__)
self.add_url_rule(rule, endpoint, f, **options)
return f
默认情况下endpoint(别名)即为函数名,得到endpoint之后,添加url与endpoint的对应关系。
比如:
‘/login' -------> login
'/index' ------> index
在没有使用functools的情况下,login,index函数传入的都是inner函数,就形成了下面的情况:
‘/login' -------> inner
'/index' ------> inner
我们通过 print(app.url_map)查看下:分开执行,分别 得到如下 结果 :
Map([<Rule '/login' (HEAD, OPTIONS, GET) -> inner>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>])
Map([<Rule '/index' (HEAD, OPTIONS, GET) -> inner>,
<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>])
这导致了文章开头的那个错误,解决办法是在写装饰器时使用functools,即:
def auth(func):
@functools.wraps(func)
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
因为使用functools时,__name__属性都是函数名本身,而不会变成inner.