配置处理 — Flask 文档

来自菜鸟教程
Flask/docs/2.0.x/config
跳转至:导航、​搜索

配置处理

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

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='192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
)

环境和调试功能

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

该环境用于向 Flask、扩展和其他程序(如 Sentry)指示 Flask 正在运行的上下文。 它由 FLASK_ENV 环境变量控制,默认为 production

FLASK_ENV 设置为 development 将启用调试模式。 flask run 将在调试模式下默认使用交互式调试器和重新加载器。 要与环境分开控制,请使用 FLASK_DEBUG 标志。

1.0 版变更: 新增 FLASK_ENV 与调试模式分开控制环境。 开发环境启用调试模式。


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

建议使用上述环境变量。 虽然可以在您的配置或代码中设置 ENVDEBUG,但强烈建议不要这样做。 flask 命令无法提前读取它们,并且某些系统或扩展可能已经根据先前的值进行了自我配置。


内置配置值

Flask 内部使用以下配置值:

ENV

应用程序在什么环境中运行。 Flask 和扩展可以根据环境启用行为,例如启用调试模式。 env 属性映射到这个配置键。 这是由 FLASK_ENV 环境变量设置的,如果在代码中设置,则可能不会按预期运行。

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

默认值:'production'

1.0 版中的新功能。

DEBUG

是否启用调试模式。 使用flask run启动开发服务器时,未处理的异常会显示交互式调试器,代码更改时会重新加载服务器。 debug 属性映射到这个配置键。 当 ENV'development' 并被 FLASK_DEBUG 环境变量覆盖时,启用此功能。 如果在代码中设置,它可能不会按预期运行。

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

默认值:True 如果 ENV'development',否则为 False

TESTING

启用测试模式。 异常被传播而不是由应用程序的错误处理程序处理。 扩展也可能会改变它们的行为以促进更容易的测试。 您应该在自己的测试中启用它。

默认值:False

PROPAGATE_EXCEPTIONS

异常会重新引发,而不是由应用程序的错误处理程序处理。 如果未设置,则在启用 TESTINGDEBUG 时隐式为真。

默认值:None

PRESERVE_CONTEXT_ON_EXCEPTION

发生异常时不要弹出请求上下文。 如果未设置,则在 DEBUG 为真时为真。 这允许调试器内省请求数据的错误,通常不需要直接设置。

默认值:None

TRAP_HTTP_EXCEPTIONS

如果没有针对 HTTPException 类型异常的处理程序,请将其重新引发以由交互式调试器处理,而不是将其作为简单的错误响应返回。

默认值:False

TRAP_BAD_REQUEST_ERRORS

尝试访问 argsform 等请求字典中不存在的密钥将返回 400 Bad Request 错误页面。 启用此选项可将错误视为未处理的异常,以便您获得交互式调试器。 这是 TRAP_HTTP_EXCEPTIONS 的更具体版本。 如果未设置,则在调试模式下启用。

默认值:None

SECRET_KEY

将用于安全签署会话 cookie 的密钥,可用于扩展或您的应用程序的任何其他安全相关需求。 它应该是一个长随机 bytesstr。 例如,将其输出复制到您的配置中:

$ python -c 'import secrets; print(secrets.token_hex())'
'192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'

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

默认值:None

SESSION_COOKIE_NAME

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

默认值:'session'

SESSION_COOKIE_DOMAIN

会话 cookie 将对其有效的域匹配规则。 如果未设置,cookie 将对 SERVER_NAME 的所有子域有效。 如果是 False,则不会设置 cookie 的域。

默认值:None

SESSION_COOKIE_PATH

会话 cookie 将对其有效的路径。 如果未设置,cookie 将在 APPLICATION_ROOT/ 下有效,如果未设置。

默认值:None

SESSION_COOKIE_HTTPONLY

为安全起见,浏览器将不允许 JavaScript 访问标记为“仅 HTTP”的 cookie。

默认值:True

SESSION_COOKIE_SECURE

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

默认值:False

SESSION_COOKIE_SAMESITE

限制 cookie 与来自外部站点的请求一起发送的方式。 可设置为 'Lax'(推荐)或 'Strict'。 请参阅 设置 Cookie 选项

默认值:None

1.0 版中的新功能。

PERMANENT_SESSION_LIFETIME

如果 session.permanent 为真,cookie 的过期时间将设置在未来的秒数。 可以是 datetime.timedeltaint

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

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

SESSION_REFRESH_EACH_REQUEST

session.permanent 为真时,控制是否随每个响应发送 cookie。 每次(默认)发送 cookie 可以更可靠地防止会话过期,但会使用更多带宽。 非常任会议不受影响。

默认值:True

USE_X_SENDFILE

提供文件时,设置 X-Sendfile 标头,而不是使用 Flask 提供数据。 某些 Web 服务器(例如 Apache)可以识别这一点并更有效地提供数据。 这仅在使用此类服务器时才有意义。

默认值:False

SEND_FILE_MAX_AGE_DEFAULT

提供文件时,将缓存控制 max age 设置为此秒数。 可以是 datetime.timedeltaint。 使用应用程序或蓝图上的 get_send_file_max_age() 在每个文件的基础上覆盖此值。

如果 None, send_file 告诉浏览器使用条件请求,而不是使用定时缓存,这通常更可取。

默认值:None

SERVER_NAME

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

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

127.0.0.1 localhost.dev

如果设置,url_for 可以生成仅具有应用程序上下文而不是请求上下文的外部 URL。

默认值:None

APPLICATION_ROOT

通知应用程序它被应用程序/网络服务器挂载在什么路径下。 这用于在请求上下文之外生成 URL(在请求内部,调度程序负责设置 SCRIPT_NAME;有关调度配置的示例,请参阅 Application Dispatching)。

如果未设置 SESSION_COOKIE_PATH,将用于会话 cookie 路径。

默认值:'/'

PREFERRED_URL_SCHEME

当不在请求上下文中时,使用此方案生成外部 URL。

默认值:'http'

MAX_CONTENT_LENGTH

不要从传入的请求数据中读取超过这么多字节。 如果未设置且请求未指定 CONTENT_LENGTH,则不会读取任何数据以确保安全。

默认值:None

JSON_AS_ASCII

将对象序列化为 ASCII 编码的 JSON。 如果禁用此选项,则从 jsonify 返回的 JSON 将包含 Unicode 字符。 这在将 JSON 呈现为模板中的 JavaScript 时具有安全隐患,并且通常应保持启用状态。

默认值:True

JSON_SORT_KEYS

按字母顺序对 JSON 对象的键进行排序。 这对于缓存很有用,因为无论 Python 的哈希种子是什么,它都能确保数据以相同的方式序列化。 虽然不推荐,但您可以禁用它以牺牲缓存为代价来提高性能。

默认值:True

JSONIFY_PRETTYPRINT_REGULAR

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

默认值:False

JSONIFY_MIMETYPE

jsonify 响应的 mimetype。

默认值:'application/json'

TEMPLATES_AUTO_RELOAD

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

默认值:None

EXPLAIN_TEMPLATE_LOADING

记录跟踪模板文件加载方式的调试信息。 这对于找出未加载模板或似乎加载了错误文件的原因很有用。

默认值:False

MAX_COOKIE_SIZE
如果 cookie 标头大于这么多字节,则发出警告。 默认为 4093。 浏览器可能会默默地忽略较大的 cookie。 设置为 0 以禁用警告。

0.4 版中的新功能: LOGGER_NAME


0.5 版中的新功能: SERVER_NAME


0.6 版新功能: MAX_CONTENT_LENGTH


0.7 版新增:PROPAGATE_EXCEPTIONSPRESERVE_CONTEXT_ON_EXCEPTION


0.8 版新增:TRAP_BAD_REQUEST_ERRORSTRAP_HTTP_EXCEPTIONSAPPLICATION_ROOTSESSION_COOKIE_DOMAINSESSION_COOKIE_PATH、[ X88X]、SESSION_COOKIE_SECURE


0.9 版的新功能: PREFERRED_URL_SCHEME


0.10 版新增:JSON_AS_ASCIIJSON_SORT_KEYSJSONIFY_PRETTYPRINT_REGULAR


0.11 版新增:SESSION_REFRESH_EACH_REQUESTTEMPLATES_AUTO_RELOADLOGGER_HANDLER_POLICYEXPLAIN_TEMPLATE_LOADING


1.0 版更改:移除了 LOGGER_NAMELOGGER_HANDLER_POLICY。 有关配置的信息,请参阅 日志记录

添加了 ENV 以反映 FLASK_ENV 环境变量。

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

添加了 MAX_COOKIE_SIZE 以控制来自 Werkzeug 的警告。


从 Python 文件配置

如果您可以将其存储在单独的文件中,那么配置将变得更加有用,理想情况下位于实际应用程序包之外。 这使得通过各种包处理工具(Deploying with Setuptools)打包和分发您的应用程序成为可能,然后最终修改配置文件。

所以一个常见的模式是这样的:

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

这首先从 yourapplication.default_settings 模块加载配置,然后用 YOURAPPLICATION_SETTINGS 环境变量指向的文件内容覆盖这些值。 这个环境变量可以在启动服务器之前在 shell 中设置:

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

下面是一个配置文件的例子:

# Example configuration
SECRET_KEY = '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'

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


从数据文件配置

也可以使用 from_file() 以您选择的格式从文件加载配置。 例如从 TOML 文件加载:

import toml
app.config.from_file("config.toml", load=toml.load)

或者来自 JSON 文件:

import json
app.config.from_file("config.json", load=json.load)

从环境变量配置

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

可以在启动服务器之前在 shell 中设置环境变量:

虽然这种方法使用起来很简单,但重要的是要记住环境变量是字符串——它们不会自动反序列化为 Python 类型。

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

import os

_mail_enabled = os.environ.get("MAIL_ENABLED", default="true")
MAIL_ENABLED = _mail_enabled.lower() in {"1", "t", "true"}

SECRET_KEY = os.environ.get("SECRET_KEY")

if not SECRET_KEY:
    raise ValueError("No SECRET_KEY set for Flask application")

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

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


配置最佳实践

前面提到的方法的缺点是它使测试更加困难。 一般而言,此问题没有单一的 100% s 解决方案,但您可以记住以下几点来改善该体验:

  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):
    TESTING = False

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

class DevelopmentConfig(Config):
    DATABASE_URI = "sqlite:////tmp/foo.db"

class TestingConfig(Config):
    DATABASE_URI = 'sqlite:///:memory:'
    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."""
    TESTING = False
    DB_SERVER = '192.168.1.56'

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

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

class DevelopmentConfig(Config):
    DB_SERVER = 'localhost'

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

有许多不同的方法,您希望如何管理配置文件取决于您。 然而,这里有一个很好的建议列表:

  • 在版本控制中保留默认配置。 在覆盖值之前,使用此默认配置填充配置或将其导入您自己的配置文件中。
  • 使用环境变量在配置之间切换。 这可以从 Python 解释器的外部完成,并使开发和部署变得更加容易,因为您可以快速轻松地在不同的配置之间切换,而根本无需接触代码。 如果你经常在不同的项目上工作,你甚至可以创建自己的脚本来激活 virtualenv 并为你导出开发配置。
  • 在生产中使用 fabric 之类的工具将代码和配置分别推送到生产服务器。 有关如何执行此操作的一些详细信息,请转到 使用 Fabric 模式进行部署。


实例文件夹

0.8 版中的新功能。


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/pythonX.Y/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 还提供了一个快捷方式,可以使用 Flask.open_instance_resource() 从实例文件夹中打开文件。

两者的示例用法:

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()