Flask config 在 flaskeleton 上的实践

Flask很赞的特点之一就是可扩展性强,非常灵活,对于 config 来说也是如此。Flask官方文档中已经提及了非常多的方法,以及一些有用的建议。我在 Flask 项目开发中的 config 实践,则是基于文档中提到的类继承方案,并通过环境变量来切换不同的 config 配置。

要求

比较好的config方案是怎样的呢?我觉得有如下几点:

从这些需求点出发,下面分享一下我在Flask项目中的实践经验。

项目结构

/project
    /configs
        __init__.py
        default.py
        development.py
        development_sample.py
        production.py
        production_sample.py
        testing.py
    /flaskeleton
        __init__.py
        ...


所有的配置文件都存放在

configs

包中,而 Flask app 则位于

flaskeleton

包。对

configs

包中不同文件的做简单的说明:

:在这里定义加载配置的函数

:默认配置

(不签入Git):用于开发的config,每个开发人员的development config可以自定义

    development.py

的模板,每当有新成员加入dev团队时,只需将其另存为

    development_xxxx.py

,然后根据自己的情况填充对应项即可

(不签入Git):用于生产服务器的config,最好是由专人来管理production.py,其他dev需要在服务器增加config项,一律向此人申请

    production.py

的模板,填好后可以scp到服务器端

:用于测试的配置,测试的 config 应该是环境无关的,所以需要签入Git中

config类继承结构

采用了基于类继承的config结构,保存默认配置的Config类作为基类,其他类继承之,如下:

    # default.py
class Config(object):
    ...

# development.py
class DevelopmentConfig(Config)
    ...

# production.py
class ProductionConfig(Config)
    ...

# testing.py
class TestingConfig(Config)
    ...


这样做的好处首先在于,通过继承达到了config复用的目的。第二个好处来自IDE,比如PyCharm可以对类中属性是否为override进行提示,如下图:

有圈圈+向上箭头标志的行就是override自父类,没有的就是自己定义的啦,一目了然。

加载策略

之前提到过,在

    config/__init__.py

中会定义用于加载config的函数,加载策略如下:

,根据

    MODE

的取值加载不同的config

环境变量不存在(或不合法),则默认加载development config

用代码表达就是:

    # coding: UTF-8
import os

def load_config():
    """加载配置类"""
    mode = os.environ.get('MODE')
    try:
        if mode == 'PRODUCTION':
            from .production import ProductionConfig
            return ProductionConfig
        elif mode == 'TESTING':
            from .testing import TestingConfig
            return TestingConfig
        else:
            from .development import DevelopmentConfig
            return DevelopmentConfig
    except ImportError, e:
        from .default import Config
        return Config


加载config

在定义好config结构之后,就可以加载了。需要尽早加载config,以便flask的一些第三方插件能够读取配置,比如Flask-SQLAlchemy:

因为在我们的 flaskeleton 项目中,使用了 Flask-Script, 所以这里就以 Flask-Script 启动为例进行介绍怎么以参数的形式选择配置:

    # manager.py
manager = Manager(create_app)

manager.add_command("runserver", Server())
manager.add_option('-c', '--config', default='TESTING',
                   help='Configuration')
manager.add_option('-n', '--app_name', default='flaskeleton',
                   help='App Name')


然后,就是 app.py 文件了。

    def create_app(config=None, app_name='flaskeleton'):
    app = Flask(app_name)
    # config
    config = load_config(config)
    app.config.from_object(config)         ...


切换config

通过改变命令行参数来切换config,在不同应用场景下有不同的方法:

    python manage.py -c DEVELOPMENT runserver -h 127.0.0.1 -p 9191


这个博客开源项目Flaskeleton已经用上了这种config策略,感兴趣的童鞋可以去看看。

参考文档/项目