装饰器的顺序在 Flask 视图中是不是重要?

Posted

技术标签:

【中文标题】装饰器的顺序在 Flask 视图中是不是重要?【英文标题】:Does the order of decorators matter on a Flask view?装饰器的顺序在 Flask 视图中是否重要? 【发布时间】:2015-03-28 01:12:50 【问题描述】:

我正在使用login_required 装饰器和另一个对输出数据进行分页的装饰器。哪个先来重要吗?

【问题讨论】:

【参考方案1】:

虽然在这种情况下无论顺序如何都可能不会有任何问题,但您可能希望 login_required 先执行,这样您就不会进行查询和对结果进行分页,这些结果会被丢弃。

装饰器将原始函数从下到上包装,因此当调用该函数时,每个装饰器添加的包装器从上到下执行。 @login_required 应该位于假定用户已登录的任何其他装饰器之下,以便在其他装饰器之前评估其条件。

@app.route() 必须始终是最顶层、最外层的装饰器。否则路由将被注册为一个不代表所有装饰器的函数。


更广泛的答案是,这取决于每个装饰器在做什么。您需要考虑程序的流程以及一个在另一个之前是否符合逻辑。

【讨论】:

【参考方案2】:

根据login_required的实现,

def login_required(func):
    @wraps(func)
    def decorated_view(*args, **kwargs):
        if current_app.login_manager._login_disabled:
            return func(*args, **kwargs)
        elif not current_user.is_authenticated():
            return current_app.login_manager.unauthorized()
        return func(*args, **kwargs)
    return decorated_view

你应该像下面那样做。

@login_required
@paginate
def view_function():
    pass

假设你有另一个装饰器 is_admin 来判断一个用户是否有管理员权限,你应该像下面那样做

@login_required
@is_admin
def view_function():
    pass

【讨论】:

【参考方案3】:

Flask 文档指定如果函数是视图并且具有route 装饰器,则顺序很重要。来自the docs:

在应用更多装饰器时,请始终记住 route() 装饰器是最外层的。

【讨论】:

【参考方案4】:

根据PEP 318,函数装饰器的语法是:

@dec2
@dec1
def func(arg1, arg2, ...):
    pass

这相当于:

def func(arg1, arg2, ...):
    pass
func = dec2(dec1(func))

dec1 在 dec2 之前调用。

您可以像这样定义这些函数进行检查:

def dec1(func):
    print 'dec1'
def dec2(func):
    print 'dec2'

@dec2
@dec1
def func():
    pass
dec1
dec2

实际上它不会出错,但是如果您首先使用login_reqired并且用户未登录,应用程序将处理数据并在login_required函数生成中止后对其进行分页

flask 中 login_required 装饰器的最佳实现是:

@paginate
@login_required
def view_function():
    pass

【讨论】:

尽管导致您的答案得出结论的所有内容都技术上正确,但您的结论绝对错误。你想把@login_required 放在@paginate 上面--让我解释一下为什么......即使装饰器确实技术上从下到上执行,你必须记住的是,当装饰器执行时,它返回一个包装器。包装器是装饰器的核心功能应该执行的地方...... 装饰器包装器从上到下执行

以上是关于装饰器的顺序在 Flask 视图中是不是重要?的主要内容,如果未能解决你的问题,请参考以下文章

Flask之基于route装饰器的路由系统(源码阅读解析)

Flask 给视图函数增加装饰器

python-flask复习—— 装饰器的坑及解决办法flask中的路由/实例化配置/对象配置/蓝图/特殊装饰器(中间件重定义错误页面)

Flask-RESTful中装饰器的使用

Flask中间件 𤋢

为 Flask 创建身份验证装饰器的问题