0

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

  1. ENV在运行flask之前直接在cmd中使用var

  2. app.config['xxx']

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

  4. app.config.from_pyfile(文件)

  5. app.config.from_envvar(文件路径_ENVVAR)

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

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

例如,如果我一起遵循以下步骤,那么假设配置将被正确应用是否安全?

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

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

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

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

4

1 回答 1

2

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

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

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

那么步骤 3 中的设置是否会正确覆盖所有先前(先前设置的)设置?这是一个好的做法吗?

的。通常,学习事物的最佳方式是尝试事物。所以我将在下面给你一个例子,使用类和继承来证明覆盖是如何工作的(你可以将它粘贴到 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

并且它是否否定了使用工厂模式的好处,因为我已经读过不使用工厂模式(例如在单元测试时)可能会导致某些配置,如果更新将无法正确应用。因此,创建工厂模式以获取应用所需配置的新对象。

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

您是正确的,弄乱了一些配置值,例如ENVDEBUG,它们是特殊的配置值可能会导致应用程序的行为不一致。有关这些特殊山谷的更多详细信息,请点击此处。因此,一旦应用程序完成设置,请尽量不要更改这些内容。在下面的建议部分中查看更多信息。


进一步说明

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

  • 例如SECRET KEY(例如,如果您使用 Cookie)
  • 切换调试模式(你绝对不想在生产中使用它,但你在开发模式下使用)
  • 使用不同的数据库(可能是不同文件的路径,如果您使用的是 SQLITE3,这在您不想使用生产数据库的测试中非常有用)
  • 使用不同的日志记录配置(您可能希望在生产中将关键信息记录到 FILE 中,但在开发中您会希望将所有内容都记录到 CONSOLE 中,以用于调试目的)
  • ETC

现在您看到了,因为您需要针对不同的配置进行不同的设置,所以您需要某种机制来在配置之间切换,这就是为什么结合使用上述所有这些方法是有用和推荐的,因为通常您会加载某种默认配置,并根据环境(生产开发等)进行相应的覆盖。

此处通过足够多的示例非常细致地描述了您实现上述所有目标的方式,这超出了本主题的范围,但我鼓励您浏览每个示例并尝试一下。

我还有一个使用 Flask 构建的开源应用程序,我在其中使用类和继承来加载基于不同环境的不同配置,并进一步定制这些配置。因此,我不仅要加载,例如,开发配置,而且如果我愿意,我什至可以进一步定制它。示例在这里,我从这里加载它们。请尝试了解我加载配置的机制,它会对您有所帮助。

编辑

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)

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


忠告

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

于 2019-09-12T10:18:31.697 回答