如何在Flask中根据服务器变量选择Config?

时间:2012-08-03 06:20:10

标签: python nginx flask gunicorn

我正在运行nginx + gunicorn + flask

我的nginx配置如下:

...

        proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header            Host $http_host;
        proxy_set_header            Stage "development";

        proxy_redirect off;

...

我的烧瓶应用程序如下:

from flask import Flask, request

from werkzeug.contrib.fixers import ProxyFix

app = Flask(__name__)

# configuration settings

if request.headers.get('Stage') == 'production':
    app.config.from_object('config.production_config')
else:
    app.config.from_object('config.development_config')

@app.route('/')
def index():
    return "hello"

app.wsgi_app = ProxyFix(app.wsgi_app)

然而,

这似乎不起作用。

我得到一个:RuntimeError:在请求上下文之外工作

设置了我的nginx,以便我可以拥有开发/生产环境,但我希望能够说这个“服务器位置”是一个开发环境,我希望Flask使用适当的配置。

2 个答案:

答案 0 :(得分:4)

应用程序配置适用于整个应用程序,而请求标头仅适用于一个请求。相同的应用程序通常处理许多请求。因此,您无法根据请求标头设置配置。

当没有请求到达应用程序时,模块级别的代码在服务器启动时执行,因此没有当前请求。这就是“在请求上下文之外工作”消息的含义。

您尝试做的事情(prod vs. dev config)最好在启动gunicorn服务器的脚本中使用环境变量。如果你想要两个同时最简单的就是运行两个gunicorn服务器。

或者,创建两个应用程序对象,在同一个进程中运行它们,并使用与以下类似的WSGI中间件进行调度:http://flask.pocoo.org/docs/patterns/appdispatch/

答案 1 :(得分:1)

这有点旧,但我想补充一下我们如何用烧瓶完成这项工作。其中大部分改编自http://flask.pocoo.org/docs/config/

在我们的config.py中,我们定义了多个类(每个环境一个):

class Config(object):
    FOO = 1
    BAR = 2

class Development(Config):
    BAR = 3

然后在我们的每个应用程序节点中,我们在gunicorn init脚本中设置了一个环境变量(对于我们来说,它存在于一个超级用户配置中但不一定是这样)。

APPLICATION_ENV='Development'

然后在初始化期间烧瓶应用程序内(仅在服务器启动时运行,而不是在请求上下文中运行):

try:
    env = os.environ['APPLICATION_ENV']
except KeyError as e:
    logging.error('Unknown environment key, defaulting to Development')
    env = 'Development'
    app.config.from_object('config.%s' % env)

现在app.config ['BAR']将是3.

我们还希望支持本地配置文件(例如,在开发人员计算机上或从厨师直接部署到机器而不存储在git中的密码)。为此,我们对上述内容进行了扩展,以便根据app.config ['LOCAL_CONFIG']参数加载本地配置。

class Development(Config):
    BAR = 3
    LOCAL_CONFIG = '/etc/localConfig.py'

然后在/etc/localConfig.py

BAR = 4

在上面的代码加载环境的初始app.config之后,再次在我们的应用初始化代码中:

if 'LOCAL_CONFIG' in app.config:
    #try to load the local configuration overrides
    if app.config.from_pyfile(app.config['LOCAL_CONFIG'], silent=True):
        logging.info('Loaded local config file at %s' % app.config['LOCAL_CONFIG'])
    else:
        logging.warning('Failed to load local config file at %s - does it exist?' % app.config['LOCAL_CONFIG'])

此时app.config ['BAR']为4.

这并不完美,因为如果你的配置中有dicts,你将只能覆盖整个dict,而不是覆盖整个dict。它确实完成了我们所需要的大部分工作。