配置管理

应用程序需要某种配置。根据应用程序环境的不同,您可能需要更改不同的设置,如切换调试模式、设置密钥以及其他此类特定于环境的内容。

Flask的设计方式通常要求应用程序启动时载入配置。您可以在代码中对配置进行硬编码,对于许多小型应用程序来说,这并没有那么糟糕,但是有更好的方法。

不管你使用何种方式载入配置,都可以使用 Flask 对象的 config 属性来操作配置的值。 Flask 本身就使用这个对象 来保存一些配置,扩展也可以使用这个对象保存配置。同时这也是你保存配置的地方。

配置入门

这个 config 实际上是字典的子类,可以像修改任何字典一样进行修改:

app = Flask(__name__)
app.config['TESTING'] = True

某些配置值也会转发到 Flask 对象,以便您可以从中读写它们:

app.testing = True

一次更新多个密钥,可以使用 dict.update() 方法:

app.config.update(
    TESTING=True,
    SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/'
)

环境和调试特点

这个 ENVDEBUG 配置值是特殊的,因为如果在应用程序开始设置后更改,它们的行为可能不一致。为了可靠地设置环境和调试模式,flask使用环境变量。

环境用于为 Flask 、扩展和其他程序(如 Sentry)指明 Flask 运行的情境是什么。环境由 FLASK_ENV 环境变量控制,默认为 production .

把 FLASK_ENV 设置为 development 可以打开调试模式。在调试模式下, flask run 会缺省使用交互调试器和重载器。如果需要脱离 环境,单独控制调试模式,请使用 FLASK_DEBUG 标示。

在 1.0 版更改: 为把 Flask 转换到开发环境并开启调试模式,设置 FLASK_ENV。

Changelog

要将flask切换到开发环境并启用调试模式,请设置 FLASK_ENV ::

$ export FLASK_ENV=development
$ flask run

(在Windows上,使用 set 而不是 export

推荐使用如上文的方式设置环境变量。虽然可以在配置或者代码中设置 环境变量无法及时地被 flask 命令读取,一个系统或者扩展就可能会使用自己已定义的环境变量。

内置配置变量

以下配置变量由 Flask 内部使用:

ENV

应用运行于什么环境。 Flask 和 扩展可以根据环境不同而行为不同,如打开或关闭调试模式。 env 属性映射了这个配置键。本变量由 FLASK_ENV 环境变量设置。如果本变量是在代码中设置的话,可能出现意外。

在生产中部署时不启用开发。

默认值: 'production'

1.0 新版功能.

Changelog
DEBUG

是否开启调试模式。使用 flask run 启动开发服务器时,遇到未能处理的 异常时会显示一个交互调试器,并且当代码变动后服务器会重启。 debug 属性映射了这个配置键。当 ENV 是 'development' 时,本变量会启用,并且会被 FLASK_DEBUG 环境变量 重载。如果本变量是在代码中设置的话,它的行为可能不符合预期。

在生产环境中部署时不启用调试模式。

默认值:当 ENV 是 'development' 时,为 True ;否则为 False 。

TESTING

开启测试模式。异常会被广播而不是被应用的错误处理器处理。扩展可能也会为 了测试方便而改变它们的行为。你应当在自己的调试中开启本变量。

默认值: False

PROPAGATE_EXCEPTIONS

异常将被重新引发,而不是由应用程序的错误处理程序处理。如果未设置,则如果 TESTINGDEBUG 启用。

默认值: None

PRESERVE_CONTEXT_ON_EXCEPTION

发生异常时不要弹出请求环境。如果没有设置,如果 DEBUG 是真的。这允许调试器在错误时反省请求数据,通常不需要直接设置。

默认值: None

TRAP_HTTP_EXCEPTIONS

如果没有处理 HTTPException 类型异常的处理器,重新引发该异常用于被交互调试器处理,而不是作为一个简单的错误响应来返回。

默认值: False

TRAP_BAD_REQUEST_ERRORS

尝试操作一个请求字典中不存在的键,如 args 和 form ,会返回一个 400 Bad Request error 页面。开启本变量,可以把这种错误作为一个未处理的 异常处理,这样就可以使用交互调试器了。本变量是一个特殊版本的 TRAP_HTTP_EXCEPTIONS 。如果没有设置,本变量会在调试模式下开启。

默认值: None

SECRET_KEY

一个密钥,用于对会话cookie进行安全签名,并可用于扩展或应用程序的任何其他安全相关需求。它应该是一个长的随机字节字符串,虽然 unicode 也是可以接受的。例如, 复制如下输出到你的配置中:

$ python -c 'import os; print(os.urandom(16))'
b'_5#y2L"F4Q8z\n\xec]/'

在发布问题或提交代码时,不要泄露密钥。

默认值: None

会话cookie的名称。如果您已有同名的cookie,则可以更改。

默认值: 'session'

会话cookie将对其有效的域匹配规则。如果本变量没有设置,那么 cookie 会被 SERVER_NAME 的所有子域认可。如果本变量设置为 False ,那么 cookie 域不会被设置。

默认值: None

认可会话 cookie 的路径。如果没有设置本变量,那么路径为 APPLICATION_ROOT ,如果 APPLICATION_ROOT 也没有设置,那么会是 / 。

默认值: None

为了安全起见,浏览器不允许javascript访问标记为“http only”的cookie。

默认值: True

如果cookie被标记为“安全”,浏览器将只通过https发送带有请求的cookie。必须通过HTTPS为应用程序提供服务,这样做才有意义。

默认值: False

限制来自外部站点的请求如何发送 cookie 。可以被设置为 'Lax' (推荐) 或者 'Strict' 。参见 Set-Cookie 选项.

默认值: None

1.0 新版功能.

Changelog
PERMANENT_SESSION_LIFETIME

如果 session.permanent 如果为真,则cookie的过期时间将设置为将来的秒数。本变量可能是一个 datetime.timedelta 或者一个 int 。

Flask的默认cookie实现验证加密签名不早于此值。

默认值: timedelta(days=31)2678400 秒)

SESSION_REFRESH_EACH_REQUEST

当 session.permanent 为真时,控制是否每个响应都发送 cookie 。每次都发送 cookie (缺省情况)可以有效地防止会话过期,但是会使用更多的带宽。会持续会话不受影响。

默认值: True

USE_X_SENDFILE

当使用 Flask 提供文件服务时,设置 X-Sendfile 头部。有些网络服务器, 如 Apache ,识别这种头部,以利于更有效地提供数据服务。本变量只有使用这 种服务器时才有效。

默认值: False

SEND_FILE_MAX_AGE_DEFAULT

当提供文件服务时,设置缓存,控制最长存活期,以秒为单位。可以是一个 datetime.timedelta 或者一个 int 。在一个应用或者蓝图上使 用 get_send_file_max_age() 可以基于单个文件重载本变 量。

默认值: timedelta(hours=12)43200 秒)

SERVER_NAME

通知应用程序它绑定到的主机和端口。需要子域路由匹配支持。

如果设置,将用于会话cookie域,如果 SESSION_COOKIE_DOMAIN 未设置。现代Web浏览器不允许为没有点的域设置cookie。若要在本地使用域,请将应路由到应用程序的任何名称添加到 hosts 文件。地址:

127.0.0.1 localhost.dev

如果这样配置了, url_for 可以为应用生成一个单独的外部 URL ,而不是 一个请求情境。

默认值: None

APPLICATION_ROOT

通知应用应用的根路径是什么。

如果 SESSION_COOKIE_PATH 没有配置,那么本变量会用于会话 cookie 路 径。

默认值 : '/'

PREFERRED_URL_SCHEME

当不在请求情境中时,使用此方案生成外部URL。

默认值: 'http'

MAX_CONTENT_LENGTH

在进来的请求数据中读取的最大字节数。如果本变量没有配置,并且请求没有指 定 CONTENT_LENGTH ,那么为了安全原因,不会读任何数据。

默认值: None

JSON_AS_ASCII

将对象序列化为ASCII编码的JSON。如果禁用此选项,JSON将作为Unicode字符串返回,或编码为 UTF-8 通过 jsonify . 在模板中将JSON呈现为JavaScript时,这会带来安全隐患,并且通常应保持启用状态。

默认值: True

JSON_SORT_KEYS

按字母顺序对JSON对象的键进行排序。这对于缓存很有用,因为它可以确保以相同的方式序列化数据,而不管Python的散列种子是什么。虽然不建议这样做,但为了可能的性能改进,您可以以缓存为代价禁用它。

默认值: True

JSONIFY_PRETTYPRINT_REGULAR

jsonify 响应将输出新行、空格和缩进,以便于人类阅读。始终在调试模式下启用。

默认值: False

JSONIFY_MIMETYPE

模仿“jsonify”的回答。

默认值: 'application/json'

TEMPLATES_AUTO_RELOAD

更改模板后重新加载模板。如果未设置,将在调试模式下启用。

默认值: None

EXPLAIN_TEMPLATE_LOADING

跟踪模板文件加载方式的日志调试信息。这有助于弄清楚为什么没有加载模板或加载了错误的文件。

默认值: False

如果cookie头大于此字节数,则发出警告。默认为 4093 . 浏览器可能会悄悄地忽略较大的cookie。设置为 0 关闭警告。

在 1.0 版更改: LOGGER_NAMELOGGER_HANDLER_POLICY 被移除。关于配置的更多内容参见 日志 。

添加 ENV 反映 FLASK_ENV 环境变量。

添加 SESSION_COOKIE_SAMESITE 来控制会话 cookie 的 SameSite 选项。

添加 MAX_COOKIE_SIZE 来控制来自于 Werkzeug 警告。

0.11 新版功能: SESSION_REFRESH_EACH_REQUEST, TEMPLATES_AUTO_RELOAD, LOGGER_HANDLER_POLICY, EXPLAIN_TEMPLATE_LOADING

0.10 新版功能: JSON_AS_ASCII, JSON_SORT_KEYS, JSONIFY_PRETTYPRINT_REGULAR

0.9 新版功能: PREFERRED_URL_SCHEME

0.8 新版功能: TRAP_BAD_REQUEST_ERRORS, TRAP_HTTP_EXCEPTIONS, APPLICATION_ROOT, SESSION_COOKIE_DOMAIN, SESSION_COOKIE_PATH, SESSION_COOKIE_HTTPONLY, SESSION_COOKIE_SECURE

0.7 新版功能: PROPAGATE_EXCEPTIONS, PRESERVE_CONTEXT_ON_EXCEPTION

0.6 新版功能: MAX_CONTENT_LENGTH

0.5 新版功能: SERVER_NAME

0.4 新版功能: LOGGER_NAME

Changelog

使用文件配置

如果您可以将配置存储在一个单独的文件中(最好位于实际应用程序包之外),那么配置将变得更加有用。这使得通过各种包处理工具打包和分发应用程序成为可能( 使用 Setuptools 部署 ), 而后修改配置文件也没有影响。

所以一个常见的模式是:

app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')

首先从 yourapplication.default_settings 模块载入配置,然后根据 YOURAPPLICATION_SETTINGS 环境变量所指向的文件的内容重载配置的值。 在启动服务器前,在 Linux 或 OS X 操作系统中,这个环境变量可以在终端中使用 export 命令来设置:

$ export YOURAPPLICATION_SETTINGS=/path/to/settings.cfg
$ python run-app.py
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader...

在 Windows 系统中使用内置的 set 来代替:

> set YOURAPPLICATION_SETTINGS=\path\to\settings.cfg

配置文件本身就是实际的python文件。稍后,只有大写的值实际存储在配置对象中。所以请确保对配置键使用大写字母。

以下是配置文件的示例:

# Example configuration
DEBUG = False
SECRET_KEY = b'_5#y2L"F4Q8z\n\xec]/'

确保在很早的时候加载配置,以便扩展能够在启动时访问配置。配置对象上还有其他方法,可以从单个文件加载。如需完整参考,请阅读 Config 对象的文档。

使用环境变量配置

除了使用环境变量指向配置文件之外,您可能会发现直接从环境控制配置值很有用(或有必要)。

在启动服务器之前,可以使用shell中的export命令在Linux或OS X上设置环境变量:

$ export SECRET_KEY='5f352379324c22463451387a0aec5d2f'
$ export DEBUG=False
$ python run-app.py
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader...

在 Windows 系统中使用内置的 set 来代替:

> set SECRET_KEY='5f352379324c22463451387a0aec5d2f'
> set DEBUG=False

虽然这种方法很容易使用,但必须记住环境变量是字符串——它们不会自动反序列化为Python类型。

以下是使用环境变量的配置文件示例:

# Example configuration
import os

ENVIRONMENT_DEBUG = os.environ.get("DEBUG", default=False)
if ENVIRONMENT_DEBUG.lower() in ("f", "false"):
    ENVIRONMENT_DEBUG = False

DEBUG = ENVIRONMENT_DEBUG
SECRET_KEY = os.environ.get("SECRET_KEY", default=None)
if not SECRET_KEY:
    raise ValueError("No secret key set for Flask application")

请注意,除了空字符串之外的任何值都将被解释为 Python 中的布尔值 True , 如果环境显式设置值为 False ,则需要注意。

确保在很早的时候加载配置,以便扩展能够在启动时访问配置。配置对象上还有其他方法,可以从单个文件加载。如需完整参考,请阅读 Config 类文档。

配置最佳实践

前面提到的方法的缺点是它使测试变得更加困难。一般来说,这个问题没有一个100%的解决方案,但是您可以记住以下几点来改进这种体验:

  1. 在函数中创建应用程序并在其上注册蓝图。这样,您就可以使用附加的不同配置创建应用程序的多个实例,这使得单元测试更加容易。您可以根据需要使用它来载入配置。
  2. 不要在导入时编写需要配置的代码。如果您将自己限制为只请求对配置的访问,则可以稍后根据需要重新配置对象。

开发/生产

大多数应用需要一个以上的配置。最起码需要一个配置用于生产服务器,另一个配置用于开发。应对这种情况的最简单的方法总是载入一个缺省配置,并把这个缺省配置作为版本控制的一部分。然后,把需要重载的配置,如前文所述,放在一个独立的文 件中:

app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
app.config.from_envvar('YOURAPPLICATION_SETTINGS')

然后你只要增加一个独立的 config.py 文件并导出 YOURAPPLICATION_SETTINGS=/path/to/config.py 即可。当然还有其他方法可选, 例如可以使用导入或子类。

在 Django 应用中,通常的做法是在文件的开关增加 from yourapplication.default_settings import * 进行显式地导入,然后手 工重载配置。你还可以通过检查一个 YOURAPPLICATION_MODE 之类的环境变量( 变量值设置为 production 或 development 等等)来导入不同的配置文件。

一个有趣的模式也是使用类和继承进行配置:

class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite:///:memory:'

class ProductionConfig(Config):
    DATABASE_URI = 'mysql://user@localhost/foo'

class DevelopmentConfig(Config):
    DEBUG = True

class TestingConfig(Config):
    TESTING = True

要启用这样的配置,您只需调用 from_object() ::

app.config.from_object('configmodule.ProductionConfig')

注意 from_object() 不实例化类对象。如果需要实例化类,例如访问属性,则必须调用 from_object() ::

from configmodule import ProductionConfig
app.config.from_object(ProductionConfig())

# Alternatively, import via string:
from werkzeug.utils import import_string
cfg = import_string('configmodule.ProductionConfig')()
app.config.from_object(cfg)

实例化配置对象允许您在配置类中使用' ' @property ' ':

class Config(object):
    """Base config, uses staging database server."""
    DEBUG = False
    TESTING = False
    DB_SERVER = '192.168.1.56'

    @property
    def DATABASE_URI(self):         # Note: all caps
        return 'mysql://user@{}/foo'.format(self.DB_SERVER)

class ProductionConfig(Config):
    """Uses production database server."""
    DB_SERVER = '192.168.19.32'

class DevelopmentConfig(Config):
    DB_SERVER = 'localhost'
    DEBUG = True

class TestingConfig(Config):
    DB_SERVER = 'localhost'
    DEBUG = True
    DATABASE_URI = 'sqlite:///:memory:'

配置的方法多种多样,由你定度。以下是一些好的建议:

  • 在版本控制中保存一个缺省配置。要么在应用中使用这些缺省配置,要么先导入 缺省配置然后用你自己的配置文件来重载缺省配置。
  • 使用一个环境变量来切换不同的配置。这样就可以在 Python 解释器外进行切换, 而根本不用改动代码,使开发和部署更方便,更快捷。如果你经常在不同的项目 间切换,那么你甚至可以创建代码来激活 virtualenv 并导出开发配置。
  • 在生产应用中使用 fabric 之类的工具,向服务器分别传送代码和配置。更 多细节参见 使用 Fabric 部署 方案。

实例文件夹

0.8 新版功能.

Changelog

Flask 0.8 引入了实例文件夹。 Flask 花了很长时间才能够直接使用应用文件夹的路径(通过 Flask.root_path )。这也是许多开发者载入应用文件夹外的 配置的方法。不幸的是这种方法只能用于应用不是一个包的情况下,即根路径指向包的内容的情况。

Flask 0.8 引入了一个新的属性: Flask.instance_path 。它指向一个新名词:“实例文件夹”。实例文件夹应当处于版本控制中并进行特殊部署。这个文件夹特别适合存放需要在应用运行中改变的东西或者配置文件。

可以要么在创建 Flask 应用时显式地提供实例文件夹的路径,要么让 Flask 自动探测 实例文件夹。显式定义使用 instance_path 参数:

app = Flask(__name__, instance_path='/path/to/instance/folder')

请记住,这里提供的路径 必须 是绝对路径。

如果 instance_path 未提供参数。使用以下默认位置:

  • 未安装的模块:

    /myapp.py
    /instance
    
  • 未安装的包:

    /myapp
        /__init__.py
    /instance
    
  • 已安装的模块或包:

    $PREFIX/lib/python2.X/site-packages/myapp
    $PREFIX/var/myapp-instance
    

    $PREFIX 是你的 Python 安装的前缀。可能是 /usr 或你的 virtualenv 的路径。可以通过打印 sys.prefix 的值来查看当前的前缀的值。

既然可以通过使用配置对象来根据关联文件名从文件中载入配置,那么就可以通过改 变与实例路径相关联的文件名来按需要载入不同配置。在配置文件中的关联路径的行 为可以在 “关联到应用的根路径”(默认的)和 “关联到实例文件夹”之间变换, 具体通过应用构建函数中的 instance_relative_config 来实现:

app = Flask(__name__, instance_relative_config=True)

下面是一个完整的示例,说明如何配置flask以从模块中预加载配置,然后在实例文件夹中的文件中覆盖配置(如果存在)::

app = Flask(__name__, instance_relative_config=True)
app.config.from_object('yourapplication.default_settings')
app.config.from_pyfile('application.cfg', silent=True)

通过 Flask.instance_path 可以找到实例文件夹的路径。Flask 还提供一 个打开实例文件夹中的文件的快捷方法。

举例说明:

filename = os.path.join(app.instance_path, 'application.cfg')
with open(filename) as f:
    config = f.read()

# or via open_instance_resource:
with app.open_instance_resource('application.cfg') as f:
    config = f.read()