配置处理

New in version 0.3.

Applications need some kind of configuration. There are different settings you might want to change depending on the application environment like toggling the debug mode, setting the secret key, and other such environment-specific things.

The way Flask is designed usually requires the configuration to be available when the application starts up. You can hardcode the configuration in the code, which for many small applications is not actually that bad, but there are better ways.

Independent of how you load your config, there is a config object available which holds the loaded configuration values: The config attribute of the Flask object. This is the place where Flask itself puts certain configuration values and also where extensions can put their configuration values. But this is also where you can have your own configuration.

配置基础

The config is actually a subclass of a dictionary and can be modified just like any dictionary:

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

Certain configuration values are also forwarded to the Flask object so you can read and write them from there:

app.debug = True

你可以使用dict.update()方法来一次性更新多个键:

app.config.update(
    DEBUG=True,
    SECRET_KEY='...'
)

内置的配置值

下列配置值是 Flask 内部使用的:

DEBUGenable/disable debug mode
TESTINGenable/disable testing mode
PROPAGATE_EXCEPTIONSexplicitly enable or disable the propagation of exceptions. 如果没有设置或显式地设置为None,当TESTINGDEBUG为真时,这个值隐式地为true。
PRESERVE_CONTEXT_ON_EXCEPTIONBy default if the application is in debug mode the request context is not popped on exceptions to enable debuggers to introspect the data. This can be disabled by this key. You can also use this setting to force-enable it for non debug execution which might be useful to debug production applications (but also very risky).
SECRET_KEYthe secret key
SESSION_COOKIE_NAMEthe name of the session cookie
SESSION_COOKIE_DOMAINthe domain for the session cookie. If this is not set, the cookie will be valid for all subdomains of SERVER_NAME.
SESSION_COOKIE_PATHthe path for the session cookie. If this is not set the cookie will be valid for all of APPLICATION_ROOT or if that is not set for '/'.
SESSION_COOKIE_HTTPONLYcontrols if the cookie should be set with the httponly flag. Defaults to True.
SESSION_COOKIE_SECURE控制cookie是否应被设置安全标志。默认为False
PERMANENT_SESSION_LIFETIMEdatetime.timedelta对象控制长期会话的生存时间。Starting with Flask 0.8 this can also be an integer representing seconds.
SESSION_REFRESH_EACH_REQUESTthis flag controls how permanent sessions are refreshed. 如果被设置为True(这是默认值),每一个请求 cookie 都会被刷新。如果设置为False,只有当会话被修改后才会发送一个set-cookie的标头。Non permanent sessions are not affected by this.
USE_X_SENDFILEenable/disable x-sendfile
LOGGER_NAMEthe name of the logger
LOGGER_HANDLER_POLICYthe policy of the default logging handler. The default is 'always' which means that the default logging handler is always active. 'debug' will only activate logging in debug mode, 'production' will only log in production and 'never' disables it entirely.
SERVER_NAMEthe name and port number of the server. 需要这个选项来支持子域名 (例如: 'myapp.dev:5000' )。 注意 localhost 不支持子域名,所以把这个选项设置为 “localhost” 没有意义。Setting a SERVER_NAME also by default enables URL generation without a request context but with an application context.
APPLICATION_ROOTIf the application does not occupy a whole domain or subdomain this can be set to the path where the application is configured to live. This is for session cookie as path value. If domains are used, this should be None.
MAX_CONTENT_LENGTHIf set to a value in bytes, Flask will reject incoming requests with a content length greater than this by returning a 413 status code.
SEND_FILE_MAX_AGE_DEFAULTDefault cache control max age to use with send_static_file() (the default static file handler) and send_file(), as datetime.timedelta or as seconds. Override this value on a per-file basis using the get_send_file_max_age() hook on Flask or Blueprint, respectively. Defaults to 43200 (12 hours).
TRAP_HTTP_EXCEPTIONSIf this is set to True Flask will not execute the error handlers of HTTP exceptions but instead treat the exception like any other and bubble it through the exception stack. This is helpful for hairy debugging situations where you have to find out where an HTTP exception is coming from.
TRAP_BAD_REQUEST_ERRORSWerkzeug’s internal data structures that deal with request specific data will raise special key errors that are also bad request exceptions. Likewise many operations can implicitly fail with a BadRequest exception for consistency. 因为在调试中,你希望准确地找出异常的原因,这个设置用于在这些情形下调试。如果这个值被设置为True,你只会得到常规的回溯。
PREFERRED_URL_SCHEMEThe URL scheme that should be used for URL generation if no URL scheme is available. 默认为http
JSON_AS_ASCIIBy default Flask serialize object to ascii-encoded JSON. If this is set to False Flask will not encode to ASCII and output strings as-is and return unicode strings. jsonify will automatically encode it in utf-8 then for transport for instance.
JSON_SORT_KEYSBy default Flask will serialize JSON objects in a way that the keys are ordered. This is done in order to ensure that independent of the hash seed of the dictionary the return value will be consistent to not trash external HTTP caches. You can override the default behavior by changing this variable. This is not recommended but might give you a performance improvement on the cost of cacheability.
JSONIFY_PRETTYPRINT_REGULARIf this is set to True (the default) jsonify responses will be pretty printed if they are not requested by an XMLHttpRequest object (controlled by the X-Requested-With header)
JSONIFY_MIMETYPEMIME type used for jsonify responses.
TEMPLATES_AUTO_RELOADWhether to check for modifications of the template source and reload it automatically. By default the value is None which means that Flask checks original file only in debug mode.
EXPLAIN_TEMPLATE_LOADINGIf this is enabled then every attempt to load a template will write an info message to the logger explaining the attempts to locate the template. This can be useful to figure out why templates cannot be found or wrong templates appear to be loaded.

More on SERVER_NAME

The SERVER_NAME key is used for the subdomain support. 因为 Flask 在得知现有服务器名之前不能 猜测出子域名部分,所以如果你想使用子域名,这个选项是必要的。这也用于会话cookie 。

Please keep in mind that not only Flask has the problem of not knowing what subdomains are, your web browser does as well. Most modern web browsers will not allow cross-subdomain cookies to be set on a server name without dots in it. So if your server name is 'localhost' you will not be able to set a cookie for 'localhost' and every subdomain of it. 请选择一个合适的服务器名,像'myapplication.local', 并添加你想要的服务器名 + 子域名到你的 host 配置或设置一个本地绑定

New in version 0.4: LOGGER_NAME

New in version 0.5: SERVER_NAME

New in version 0.6: MAX_CONTENT_LENGTH

New in version 0.7: PROPAGATE_EXCEPTIONS, PRESERVE_CONTEXT_ON_EXCEPTION

New in version 0.8: TRAP_BAD_REQUEST_ERRORS, TRAP_HTTP_EXCEPTIONS, APPLICATION_ROOT, SESSION_COOKIE_DOMAIN, SESSION_COOKIE_PATH, SESSION_COOKIE_HTTPONLY, SESSION_COOKIE_SECURE

New in version 0.9: PREFERRED_URL_SCHEME

New in version 0.10: JSON_AS_ASCII, JSON_SORT_KEYS, JSONIFY_PRETTYPRINT_REGULAR

New in version 0.11: SESSION_REFRESH_EACH_REQUEST, TEMPLATES_AUTO_RELOAD, LOGGER_HANDLER_POLICY, EXPLAIN_TEMPLATE_LOADING

从文件配置

Configuration becomes more useful if you can store it in a separate file, ideally located outside the actual application package. This makes packaging and distributing your application possible via various package handling tools (Deploying with Setuptools) and finally modifying the configuration file afterwards.

So a common pattern is this:

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

它首先从yourapplication.default_settings模块加载配置,然后用YOURAPPLICATION_SETTINGS环境变量指向的文件的内容覆盖其值。This environment variable can be set on Linux or OS X with the export command in the shell before starting the server:

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

On Windows systems use the set builtin instead:

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

The configuration files themselves are actual Python files. Only values in uppercase are actually stored in the config object later on. So make sure to use uppercase letters for your config keys.

Here is an example of a configuration file:

# Example configuration
DEBUG = False
SECRET_KEY = '?\xbf,\xb4\x8d\xa3"<\x9c\xb0@\x0f5\xab,w\xee\x8d$0\x13\x8b83'

Make sure to load the configuration very early on, so that extensions have the ability to access the configuration when starting up. There are other methods on the config object as well to load from individual files. For a complete reference, read the Config object’s documentation.

配置的最佳实践

The downside with the approach mentioned earlier is that it makes testing a little harder. There is no single 100% solution for this problem in general, but there are a couple of things you can keep in mind to improve that experience:

  1. Create your application in a function and register blueprints on it. That way you can create multiple instances of your application with different configurations attached which makes unittesting a lot easier. You can use this to pass in configuration as needed.
  2. Do not write code that needs the configuration at import time. If you limit yourself to request-only accesses to the configuration you can reconfigure the object later on as needed.

开发 / 生产

Most applications need more than one configuration. There should be at least separate configurations for the production server and the one used during development. The easiest way to handle this is to use a default configuration that is always loaded and part of the version control, and a separate configuration that overrides the values as necessary as mentioned in the example above:

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

然后你只需要添加一个独立的config.py文件并export YOURAPPLICATION_SETTINGS=/path/to/config.py,你就完成了。However there are alternative ways as well. For example you could use imports or subclassing.

What is very popular in the Django world is to make the import explicit in the config file by adding from yourapplication.default_settings import * to the top of the file and then overriding the changes by hand. You could also inspect an environment variable like YOURAPPLICATION_MODE and set that to production, development etc and import different hardcoded files based on that.

An interesting pattern is also to use classes and inheritance for configuration:

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

To enable such a config you just have to call into from_object():

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

There are many different ways and it’s up to you how you want to manage your configuration files. However here a list of good recommendations:

  • Keep a default configuration in version control. Either populate the config with this default configuration or import it in your own configuration files before overriding values.
  • Use an environment variable to switch between the configurations. This can be done from outside the Python interpreter and makes development and deployment much easier because you can quickly and easily switch between different configs without having to touch the code at all. If you are working often on different projects you can even create your own script for sourcing that activates a virtualenv and exports the development configuration for you.
  • 使用fabric之类的工具在生产环境中独立地向生产服务器推送代码和配置。参阅使用Fabric部署模式来获得更详细的信息。

实例文件夹

New in version 0.8.

Flask 0.8 introduces instance folders. Flask for a long time made it possible to refer to paths relative to the application’s folder directly (via Flask.root_path). This was also how many developers loaded configurations stored next to the application. Unfortunately however this only works well if applications are not packages in which case the root path refers to the contents of the package.

Flask 0.8引入一个新的属性:Flask.instance_path它表示一个新的概念叫做“实例文件夹”。The instance folder is designed to not be under version control and be deployment specific. It’s the perfect place to drop things that either change at runtime or configuration files.

You can either explicitly provide the path of the instance folder when creating the Flask application or you can let Flask autodetect the instance folder. For explicit configuration use the instance_path parameter:

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

Please keep in mind that this path must be absolute when provided.

If the instance_path parameter is not provided the following default locations are used:

  • Uninstalled module:

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

    /myapp
        /__init__.py
    /instance
    
  • Installed module or package:

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

    $PREFIX is the prefix of your Python installation. This can be /usr or the path to your virtualenv. You can print the value of sys.prefix to see what the prefix is set to.

Since the config object provided loading of configuration files from relative filenames we made it possible to change the loading via filenames to be relative to the instance path if wanted. The behavior of relative paths in config files can be flipped between “relative to the application root” (the default) to “relative to instance folder” via the instance_relative_config switch to the application constructor:

app = Flask(__name__, instance_relative_config=True)

Here is a full example of how to configure Flask to preload the config from a module and then override the config from a file in the config folder if it exists:

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

The path to the instance folder can be found via the Flask.instance_path. Flask also provides a shortcut to open a file from the instance folder with 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()