flask自定义decorator的坑点
在一次开发中需要做一个权限验证的修饰器,由于之前并没有太多的flask编程经验,没有写过这种修饰器,于是便直接写出了以下的代码:
1 | def is_admin(func): |
写完后直接运行报错:
1 | existing endpoint function: %s' % endpoint) |
一开始的时候百思不得其解,并不懂这个错误出现的原因。后来联系报错的提示为已经存在了一个注册过的函数admin.wrapper.
可以判断为,经过修饰器修饰后,当传入flask自己的修饰器后修饰器获取到的当前函数的名称为wrapper,所以所有被这个修饰器修饰过得函数传入flask的修饰器中获取到的函数名都是wrapper,因此产生了冲突从而报错。
查看报错的地方的源码,位于app.py中:
1 | def add_url_rule(self, rule, endpoint=None, view_func=None, |
这里的view_functions是一个dict,存储endpoint-view_func键值对。而endpoint是指一个标记各个url的一个字符串,通常为函数的名称。endpoint与不同的函数一一对应。
出错的原因在于相同的endpoint被指向了两次,且指向的函数不同,但是这两个不同的函数却拥有相同的名字name,因此便对应了相同的endpoint。所以便导致了重复出现的错误。
那么怎么解决这个问题?这里使用了一个叫做functools的库中定义的一个修饰器@functool.wraps.
更改后的代码为:1
2
3
4
5
6
7def is_admin(func):
def wrapper(*args,**kargs):
if not session['is_admin']:
return redirect('/admin/login')
return func(args,kargs)
return wrapper
再次调试可以看到这次程序运行后对应的函数的name不同,从而没有再出现bug。再次调试可以发现最后的函数的name与对应的endpoint值均不同。
注:@functools.wraps(func)的作用就是保留原有函数的名称和docstring
参考
后记
经过这次拍错发现自己对flask的实现机制产生了浓厚的兴趣。。。。那就立个flag,今年要把flask的源码好好看一看,至少弄懂flask背后的设计原理。