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

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

【问题讨论】:

    标签: python flask python-decorators flask-login


    【解决方案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 上面--让我解释一下为什么......即使装饰器确实技术上从下到上执行,你必须记住的是,当装饰器执行时,它返回一个包装器。包装器是装饰器的核心功能应该执行的地方...... 装饰器包装器从上到下执行
          猜你喜欢
          • 1970-01-01
          • 2019-04-17
          • 1970-01-01
          • 2012-02-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-19
          • 2014-10-12
          • 2021-09-27
          相关资源
          最近更新 更多