说吧,我有一个手工制作的@login-required
装饰器:
from functools import wraps
def login_required(decorated_function):
"""Decorator to check if user is logged in."""
@wraps(decorated_function)
def wrapper(*args, **kwargs):
if False: # just to check it's working
return decorated_function(*args, **kwargs)
else:
flash('You need to login, to access this page')
return redirect(url_for('login'))
return wrapper
和一个函数,装饰有@app.route()
and @login_required
(端点为login
为简洁起见省略):
@app.route('/')
@login_required
def index():
return "Hello!"
现在,如果我尝试访问/
,正如预期的那样,它不会让我这样做,并且会重定向到登录页面。
不过,如果我滑动装饰器的顺序,即:
@login_required
@app.route('/')
def index():
return "Hello!"
然后我就可以访问/
,尽管我不应该这样。
我知道关于该主题的 Flask 文档 http://flask.pocoo.org/docs/0.12/patterns/viewdecorators/#login-required-decorator states:
当应用更多的装饰器时,永远记住route()装饰器是最外面的。
我也见过other https://stackoverflow.com/questions/28575234/login-required-trouble-in-flask-app 问题 https://stackoverflow.com/questions/25288773/login-required-decorator-doesnt-work-flask-login-permits-anonymous-users在同一问题上。
我好奇的不是正确的方法是什么(@app.route()
装饰器必须在最外面 - 明白了),而是为什么它会这样工作(即它背后的机制是什么)。
我看了一下@app.route()
源代码 https://github.com/pallets/flask/blob/master/flask/app.py:
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
这个答案 https://stackoverflow.com/a/1594484/8554766,或多或少帮助我理解了装饰器的机制。不过,我以前从未见过函数只是返回(没有调用它),所以我自己做了一个小实验(当然,结果是可行的):
def my_decorator():
def decorator (function):
return function
return decorator
@my_decorator()
def test():
print('Hi')
test()
所以,我想了解一下:
- 为什么装饰器的顺序在上面的确切情况下很重要
@app.route()
和一般的其他装饰器(我猜这是相同的答案)?让我困惑的是@app.route()
只需将 url 规则添加到应用程序(即self.add_url_rule(rule, endpoint, f, **options)
并返回函数,就是这样,那么为什么顺序很重要呢?
- Does
@app.route()
覆盖它上面的所有装饰器(如果是的话怎么办)?
我也是aware https://stackoverflow.com/a/28204335/8554766,装饰器应用顺序是从下到上,尽管对我来说这并没有让事情变得更清晰。我缺少什么?