在完成第一次配置分配后覆盖应用程序配置是否安全(并且它不会否定 facotry 模式的好处)?

Is it safe to overwrite app config after 1st config assignment is made (and doesn't it negate the benefit of facotry pattern)?

您好,我们有几种方法可以在 Flask 中设置应用程序配置。

  1. ENV 在cmd中直接var 运行 flask

  2. app.config['xxx']

  3. app.config.from_object(模块或class)

  4. app.config.from_pyfile (文件)

  5. app.config.from_envvar (FILEPATH_ENVVAR)

我读到过,例如在单元测试时,最好实现工厂模式,因为某些配置在被覆盖时不起作用。

所以我想知道从上面使用多种方法是否安全?

例如,如果我同时执行以下步骤,那么假设配置将被正确应用是否安全?

第 1 步:在 运行 应用程序之前使用方法 1(例如设置 ENV var 密钥 以设置 ENV可以在第 2 步的代码中检查的 var,以决定是否应用 dev/prod 配置设置 class 来设置 ENV var PATH_TO_SOMECONFIGFILE)

第 2 步:在初始化应用程序对象后,立即使用方法 3(设置默认生产设置 检查 ENV 在上述步骤中设置的 var 以调用适当的 dev/prod class).

第 3 步:在上述步骤之后,立即使用方法 4 或 5 更新配置设置

那么第 3 步中的设置是否会正确地覆盖所有以前的(以前设置的)设置?这是好的做法吗?并且它不会否定使用工厂模式的好处,因为我已经读过不使用工厂模式(例如在单元测试时)可能会导致某些配置如果更新不会正确应用。因此,创建工厂模式以获取应用了所需配置的新对象。

我将首先回答您的问题,然后我将继续解释有关配置最佳实践的一些内容。

So I am wondering if it is safe to use multiple methods from above?

。事实上,建议 您使用多种方式加载您的配置(请参阅下文原因)。

So will the settings from step 3 overwrite all previous (previously set) settings correctly? And is this good practice?

。通常学习事物的最好方法是尝试。所以我将在下面给你一个例子,使用 类 和继承只是为了证明覆盖是如何工作的(你可以将它粘贴到 Python 模块和 运行 它,假设你已经安装了 Flask ),但您应该继续试验您已阅读的上述所有方法,并将它们混合搭配以巩固您的知识。

from flask import Flask


class Config:
    LOGGING_CONFIGURATION = None
    DATABASE = None

class DevelopmentConfig(Config):
    LOGGING_CONFIGURATION = 'Development'
    DATABASE = 'development.db'

class TestConfig(Config):
    LOGGING_CONFIGURATION = 'Test'
    DATABASE = 'test.db'


def create_app(config):
    app = Flask(__name__)
    app.config.from_object(Config)  # we load the default configuration
    print(app.config['LOGGING_CONFIGURATION'], app.config['DATABASE'])
    app.config.from_object(config)  # we override with the parameter config
    print(app.config['LOGGING_CONFIGURATION'], app.config['DATABASE'])
    return app


if __name__ == '__main__':
    app = create_app(DevelopmentConfig)
    test_app = create_app(TestConfig)  # you do this during tests

产出

None None
Development development.db
None None
Test test.db

And Doesn't it negate the benefit of using factory pattern since I have read that not using factory pattern (for example while unit testing) could result in certain config if updated will not apply correctly. Hence create factory pattern to get fresh object with the needed config applied.

。你在这里混淆了东西,加载配置和使用应用程序工厂并不相互排斥。事实上,他们是一起工作的。

你是对的,搞乱了一些配置值,比如 ENV and DEBUG, which are special config values may cause the application to behave inconsistently. More details on those special vales here。因此,一旦应用程序完成设置,请尽量不要更改它们。在下面的 建议 部分中查看更多信息。


进一步说明

Flask 的设计方式通常要求配置在应用程序启动时可用,并且您通常需要某种配置,因为根据您的环境,您可能想要更改不同的设置,例如:

  • 例如 SECRET KEY(如果您正在使用 Cookie)
  • 切换 DEBUG mode(你肯定不想在生产中使用它,但你在开发模式中使用)
  • 使用不同的 DATABASE(这可能是不同文件的路径,如果您使用的是 SQLITE3,它在测试中非常有用,您不想使用生产数据库)
  • 使用不同的 logging configuration(您可能希望在生产中将关键信息记录到文件中,但在开发中您将希望将所有内容记录到控制台,以用于调试目的)

现在你明白了,因为不同的配置需要不同的设置,所以你需要某种机制来在配置之间切换,这就是为什么要使用上面所有这些方法的原因combined 很有用并且值得推荐,因为通常你会加载某种 DEFAULT 配置,并根据环境相应地覆盖(生产发展,等等)。

通过足够的示例非常细致地描述了您实现上述所有内容的方法 here,这超出了本主题的范围,但我鼓励您仔细阅读每个示例并尝试一下.

我也有一个open source app, built with Flask, where I've used classes and inheritance to load different configurations based on different environments and went even further to customise those as well. So not only do I load, say, the DEVELOPMENT configuration, but I even customise it further should I want to. Examples are here, and I load them from here。尝试理解我加载配置的机制,它会对你有所帮助。

编辑:

config 对象只是字典的一个子类,它有额外的方法来帮助您从不同的地方(您在上面看到的那些地方)加载配置:

  • 加载或覆盖配置的方式并不重要。所有设置都将加载到 config 字典中。这属于 Flask 对象。这是您的配置所在的位置。
  • 所以你是否这样做并不重要:
  # override a setting if it exists or add it if it doesn't
  # just like you would do in a normal dictionary
  app.config[key] = value

  # this will either override all the values that are loaded
  # from that object or it will add them
  app.config.from_pyobject(object)

  # same as above, and the same goes for any method you use to add/override
  app.config.from_pyfile(filename)

此处未列出的任何其他可能 load/override 设置的方法也是如此。它们都具有相同的优先级,请注意覆盖的顺序,最后加载的配置是应用程序将使用的配置。


忠告

尝试加载您的配置及其所有核心设置,无论您的环境如何,只要您的应用程序启动,从那时起就不要更改它们.如果你发现你在应用程序的不同部分改变了很多设置,在应用程序 运行ning 之后(即你做了很多 app[value] = another_value),试着重新考虑你的设计,因为那是一个不稳定的实现。如果应用程序的一部分需要应用程序的另一部分尚未设置的设置怎么办?不要那样做。