【问题标题】:How to access app.config in a blueprint?如何在蓝图中访问 app.config?
【发布时间】:2013-08-15 09:28:49
【问题描述】:

我正在尝试访问包 api 中的蓝图 authorisation.py 中的访问应用程序配置。我正在初始化__init__.py 中的蓝图,它在authorisation.py 中使用。

__init__.py

from flask import Blueprint
api_blueprint = Blueprint("xxx.api", __name__, None)
from api import authorisation

授权.py

from flask import request, jsonify, current_app

from ..oauth_adapter import OauthAdapter
from api import api_blueprint as api

client_id = current_app.config.get('CLIENT_ID')
client_secret = current_app.config.get('CLIENT_SECRET')
scope = current_app.config.get('SCOPE')
callback = current_app.config.get('CALLBACK')

auth = OauthAdapter(client_id, client_secret, scope, callback)


@api.route('/authorisation_url')
def authorisation_url():
    url = auth.get_authorisation_url()
    return str(url)

我收到 RuntimeError: working outside of application context

我明白为什么会这样,但是访问这些配置设置的正确方法是什么?

----更新---- 暂时,我已经这样做了。

@api.route('/authorisation_url')
def authorisation_url():
    client_id, client_secret, scope, callback = config_helper.get_config()
    auth = OauthAdapter(client_id, client_secret, scope, callback)
    url = auth.get_authorisation_url()
    return str(url)

【问题讨论】:

    标签: flask


    【解决方案1】:

    在蓝图视图中使用flask.current_app 代替app

    from flask import current_app
    
    @api.route("/info")
    def get_account_num():
        num = current_app.config["INFO"]
    

    current_app 代理仅在请求的上下文中可用。

    【讨论】:

    • 请注意,current_app 代理仅在请求上下文中可用。
    • @sephr 有关如何从其他地方访问该请求上下文的任何提示(不将其作为参数传递,而是作为某种全局参数传递)?
    • 解决问题RuntimeError: Working outside of application context,可以看看这个link
    【解决方案2】:

    重载record 方法似乎很简单:

    api_blueprint = Blueprint('xxx.api',  __name__, None)
    api_blueprint.config = {}
    
    @api_blueprint.record
    def record_params(setup_state):
      app = setup_state.app
      api_blueprint.config = dict([(key,value) for (key,value) in app.config.iteritems()])
    

    【讨论】:

    • 对于 Python 3 使用:app.config.items() 而不是 app.config.iteritems()
    • 您好,我需要调用或注册record_params吗,我试过了,但是没有用。非常感谢。
    • 如果您需要访问应用程序(例如获取用于设置蓝图的配置),这很棒!
    • api_blueprint 没有属性 config。如果我想这样做,我想我必须setattr?
    【解决方案3】:

    要建立在tbicr's 答案的基础上,下面是一个覆盖register method 示例的示例:

    from flask import Blueprint
    
    auth = None
    
    class RegisteringExampleBlueprint(Blueprint):
        def register(self, app, options, first_registration=False):
            global auth
    
            config = app.config
            client_id = config.get('CLIENT_ID')
            client_secret = config.get('CLIENT_SECRET')
            scope = config.get('SCOPE')
            callback = config.get('CALLBACK')
    
            auth = OauthAdapter(client_id, client_secret, scope, callback)
    
            super(RegisteringExampleBlueprint,
                  self).register(app, options, first_registration)
    
    the_blueprint = RegisteringExampleBlueprint('example', __name__)
    

    还有一个使用record decorator的例子:

    from flask import Blueprint
    from api import api_blueprint as api
    
    auth = None
    
    # Note there's also a record_once decorator
    @api.record
    def record_auth(setup_state):
        global auth
    
        config = setup_state.app.config
        client_id = config.get('CLIENT_ID')
        client_secret = config.get('CLIENT_SECRET')
        scope = config.get('SCOPE')
        callback = config.get('CALLBACK')
    
        auth = OauthAdapter(client_id, client_secret, scope, callback)
    

    【讨论】:

    • '@api.record' 对我不起作用,. 'api' 来自哪个命名空间?
    • 抱歉没有从问题from api import api_blueprint as api的行中复制它
    【解决方案4】:

    蓝图有register method,当你register blueprint时调用它。所以你可以重写这个方法或者使用record decorator来描述依赖于app的逻辑。

    【讨论】:

      【解决方案5】:

      current_app 方法很好,但您必须有一些请求上下文。如果你没有一个(例如测试之类的前期工作),你最好放置

      with app.test_request_context('/'):

      在此current_app 电话之前。

      您将拥有 RuntimeError: working outside of application context ,而不是。

      【讨论】:

      • 当应用程序是在工厂中创建的,因此无法导入“应用程序”(或任何所谓的烧瓶应用程序)时怎么办?在请求内部没有问题,因为在请求期间有一个应用程序上下文,但是在定义需要应用程序配置的请求逻辑之外的部分时。如果您不能使用应用程序创建上下文,如何访问应用程序配置?
      【解决方案6】:

      您要么需要导入由Flask() 返回的主要app 变量(或您所称的任何变量):

      from someplace import app
      app.config.get('CLIENT_ID')
      

      或者在请求中这样做:

      @api.route('/authorisation_url')
      def authorisation_url():
          client_id = current_app.config.get('CLIENT_ID')
          url = auth.get_authorisation_url()
          return str(url)
      

      【讨论】:

      • 是的,我不想做这两个。第一种是创建交叉引用,第二种方法不是 DRY。
      • @ChirdeepTomar 如果第一种方法是创建循环导入(这会破坏应用程序),那么您的应用程序的结构就有问题。
      • @DanielChatfield 这根本不是真的。 app 对象是注册蓝图的对象。建议蓝图正确然后导入应用程序对象将总是导致循环依赖。请参阅其他答案以了解正确的策略。
      • @sholsapp 我知道它会创建一个循环导入(就像它在烧瓶文档中所做的那样:flask.pocoo.org/docs/patterns/packages),我说如果它创建了一个循环导入会破坏应用程序.
      【解决方案7】:

      您还可以将蓝图包装在一个函数中并将app 作为参数传递:

      蓝图:

      def get_blueprint(app):
          bp = Blueprint()
          return bp
      

      主要:

      from . import my_blueprint
      app.register_blueprint(my_blueprint.get_blueprint(app))
      

      【讨论】:

      • 我试过这个,但我得到一个“内部服务器错误”。
      • 这种方法有什么缺点吗?
      • @Tuukka:我不记得有什么特别的缺点,我用它有点太久了。当您在多个应用程序中使用蓝图时,使用 flask.current_app 可能会有一些优势。我建议如果这种方法可以解决您使用它的问题,Flask 不会强制执行特定方法。
      【解决方案8】:

      我知道这是一个旧线程。但是在编写烧瓶服务时,我使用了这样的方法来做到这一点。它比上面的解决方案更长,但它使您可以自己使用自定义类。坦率地说,我喜欢编写这样的服务。

      第 1 步:

      我在不同的模块文件中添加了一个结构,我们可以在其中将类结构设为单例。我从已经讨论过的这个线程中得到了这个类结构。 Creating a singleton in Python

      class Singleton(type):
          _instances = {}
      
          def __call__(cls, *args, **kwargs):
              if cls not in cls._instances:
                  cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
              else:
                  cls._instances[cls].__init__(*args, **kwargs)
      
              return cls._instances[cls]
      

      第 2 步:

      然后我从上面定义的 Singleton 类创建了一个 Singleton EnvironmentService 类,只是为了我们的目的。与其重新创建此类类,不如创建一次并在其他模块、路由等导入中使用它们。我们可以使用相同的引用访问该类。

      from flask import Config
      from src.core.metaclass.Singleton import Singleton
      
      
      class EnvironmentService(metaclass=Singleton):
          __env: Config = None
      
          def initialize(self, env):
              self.__env = env
              return EnvironmentService()
      
          def get_all(self):
              return self.__env.copy()
      
          def get_one(self, key):
              return self.__env.get(key)
      

      第 3 步:

      现在我们将服务包含在我们项目根目录的应用程序中。 此过程应在路由之前应用。

      from flask import Flask
      from src.services.EnvironmentService import EnvironmentService
      
      app = Flask(__name__)
      
      # Here is our service
      env = EnvironmentService().initialize(app.config)
      
      # Your routes...
      

      用法:

      是的,我们现在可以从其他路线访问我们的服务。

      from src.services.EnvironmentService import EnvironmentService
      
      key = EnvironmentService().get_one("YOUR_KEY")
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-29
        • 2011-08-24
        • 2012-11-07
        • 1970-01-01
        • 2011-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多