Flask:为什么 app.route() 装饰器应该总是在最外面?

2024-04-04

说吧,我有一个手工制作的@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,装饰器应用顺序是从下到上,尽管对我来说这并没有让事情变得更清晰。我缺少什么?


你自己几乎已经解释清楚了! :-)app.route does

self.add_url_rule(rule, endpoint, f, **options)

但关键是f这是装饰的任何功能。如果您申请app.route首先,它为原始函数添加一个 URL 规则(没有登录装饰器)。登录装饰器包装了该函数,但是app.route已经存储了原始的未包装版本,因此包装无效。

设想“展开”装饰器可能会有所帮助。想象一下你是这样做的:

# plain function
def index():
    return "Hello!"

login_wrapped = login_required(index)         # login decorator
both_wrapped = app.route('/')(login_wrapped)  # route decorator

这是先进行登录再进行路由的“正确”方式。在这个版本中,该功能app.routesee 已经用登录包装器包装了。错误的做法是:

# plain function
def index():
    return "Hello!"

route_wrapped = app.route('/')(index)        # route decorator
both_wrapped = login_wrapped(route_wrapped)  # login decorator

在这里你可以看到什么app.route看到的只是普通的未包装版本。事实上,该函数是later用登录装饰器包裹没有任何效果,因为那时路由装饰器已经完成了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flask:为什么 app.route() 装饰器应该总是在最外面? 的相关文章

随机推荐

  • 使用文件夹结构迭代 S3 存储桶中的文件

    我有一个 S3 存储桶 在存储桶内 我们有一个 2018 年的文件夹 以及我们每个月和每天收集的一些文件 例如 2018 3 24 2018 3 25 等等 我们没有将日期放入每天存储桶内的文件中 基本上 我想遍历存储桶并使用文件夹结构按
  • 张量流中值

    如何计算张量流中列表的中值 喜欢 node tf median X X 是占位符在numpy中 我可以直接使用np median来获取中值 如何在tensorflow中使用numpy运算 用于计算数组的中位数tensorflow你可以使用p
  • Angular.js - 使用间隔应用过滤器

    我正在对日期时间对象使用自定义 angular js 过滤器 function relativeTimeFilter return function dateObj return getRelativeDateTimeString date
  • 与 SVN 上游同步工作[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在开发一个使用开源项目代码的项目 要求之一是将尽可能多的代码推回到上游 远程项目正在使用 Subversion 不是很好 我当前的
  • 为什么我不能转换 ref 参数?

    我有一个带有 ref 控件类型参数的方法 我想通过传递 ref 按钮类型参数来调用该方法 那么编译器不接受这一点 我必须将引用控件类型更改为引用按钮类型 Why 因为这会带来很多问题 public void DoDarkMagic ref
  • 克隆 MongoDB 中的集合

    我想克隆 MongoDB 集合并将其以不同的名称保存在同一服务器上 例如 现在我有以下集合 demo1 categories demo1 users 和 demo2 users 我想要一个与 demo1 categories 相同的 dem
  • 如何转义双引号作为 NUnit TestCase 的参数?

    我尝试为用 VB net 编写的 NUnit 测试编写以下 TestCase
  • 如何将同义词词典添加到mysql全文搜索?

    这样 如果我搜索术语 男士 术语 绅士 就会匹配 我试过这个 SELECT FROM cart product WHERE MATCH product name product description product brand metal
  • AppSync BatchResolver AssumeRole 错误

    我正在尝试使用新的 DynamoDB BatchResolvers 写入 AppSync 解析器中的两个 DynamoDB 表 当前使用 Lambda 函数来执行此操作 但是 在查看 CloudWatch 日志时 我收到以下权限错误 Use
  • Patindex() 函数的用法

    我在用patindex用于 MD 或 DO 的模式搜索 下面的语句返回3 我是否以错误的方式使用它 或者是否有其他检查条件的方法 select PATINDEX MD DO FHoisegh MD select T Value from v
  • angular2 – 通过自定义管道使用全局服务

    我正在玩一点 Angular 2 到目前为止 我构建了一个拥有接口的全局服务 其他组件正在使用这个全局服务的接口 如果通过组件更改界面 则子组件的界面也会更改 现在我正在尝试通过管道来处理这个问题 但是 当我通过子组件更改接口值时 其他组件
  • QSerialPort可以读取超过512字节的数据吗?

    我想使用 QSerialPort 读取从设备传输的数据 设备每次发送一帧4000个数据字节 我尝试使用以下简单的代码 QSerialPort serialPort char receivedData 4000 int numRead 0 M
  • 将响应结果作为数组而不是 Web 服务中的对象获取

    有一个 php 应用程序将从我创建的 Web 服务中读取结果 他们想要的 xml 响应就像
  • 如何在非阻塞套接字上处理 OpenSSL SSL_ERROR_WANT_READ / WANT_WRITE

    OpenSSL 库允许使用 SSL read 从底层套接字读取数据并使用 SSL write 写入数据 这些函数可能会返回 SSL ERROR WANT READ 或 SSL ERROR WANT WRITE 具体取决于它们的 ssl 协议
  • 我在设置 Windows 服务时遇到问题

    我正在尝试设置 Windows 服务 但是当我构建设置时 输出是这样的 Build started Project TwitterService Configuration Debug Any CPU TwitterService gt C
  • 使用 myBatis 从数据库中以 byte[] 的形式获取 blob

    我在一个项目中使用 spring MyBatis 1 2 0 其中有一个查询从 Oracle 11g 数据库中的 BLOB 字段获取数据 我想以字节数组 byte 的形式检索该字段 我的代码是
  • 平均执行时间

    有没有什么好的 GNU 方法来测量某些命令行程序的平均 最坏情况 最好情况 执行时间 我有图像过滤器 未指定数量的图片 使用 bash 中的 for 循环过滤它们 到目前为止我正在使用time 但我找不到如何获取一些统计数据的方法 您可以将
  • 将 XYZ 点云转换为灰度图像

    每个人 我正在尝试使用 python 将点云 X Y Z 转换为灰度图像 我了解到灰度图像可以由 Numpy 数组生成 但我现在拥有的是一组包含 X Y 和高度的点 我想根据 X Y 和灰度值 即高度 生成灰度图像 有人能给我一个关于这个的
  • 我的驱动程序模块的内核输出奇怪的 dmesg

    从我之前的问题为什么模块加载失败 dev scull0 没有这样的设备或地址 https stackoverflow com questions 62019834 why does module failed to load dev scu
  • Flask:为什么 app.route() 装饰器应该总是在最外面?

    说吧 我有一个手工制作的 login required装饰器 from functools import wraps def login required decorated function Decorator to check if u