应用配置
1. 加载配置
app.config
用于设置配置, 该属性继承自dict
, 可以以字典形式赋值取值
代码示例
from datetime import timedelta from flask import Flask, session app = Flask(__name__) app.secret_key = 'test' # config属性用于设置配置 app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7) @app.route('/') def index(): # 设置session 用于测试配置是否生效 session['name'] = 'zs' # 读取配置 print(app.config.get('PERMANENT_SESSION_LIFETIME')) return "index" if __name__ == '__main__': app.run(debug=True)
- 实际开发中, 应该将配置封装起来, 方便进行统一的管理, 类似Django的settings文件
- Flask提供了多种封装方式, 这里先介绍一种常用的方案 -- 从对象中加载配置
从对象中加载配置
实际开发中, 项目往往存在多套配置
- 开发环境配置
- 生产环境配置
- 测试环境配置
- ...
- 各种环境的配置既有相同也有不同, 大量相同的配置会出现代码冗余
- 从对象中加载配置
- 配置封装方案之一, 以面向对象的形式 封装配置, 有利于 减少重复代码 以及 代码解耦合
代码示例
- 定义配置文件
config.py
, 在文件中将应用配置 以类的形式 封装起来
# config.py from datetime import timedelta class BaseConfig: """配置基类 可以将相同的配置抽取到基类中, 减少重复代码""" # 定义和配置同名的类属性 PERMANENT_SESSION_LIFETIME = timedelta(days=7) class DevelopmentConfig(BaseConfig): """开发环境""" SQL_URL = '127.0.0.1:3306/test1' # 数据库地址 class ProductionConfig(BaseConfig): """生产环境""" SQL_URL = '222.10.15:3306/users' # 数据库地址
- 主文件
main.py
从对象中加载封装的配置app.config.from_object()
# main.py from datetime import timedelta from flask import Flask app = Flask(__name__) # 从对象中加载配置 # 优点: 面向对象的设计有利于 减少重复代码 以及 代码解耦合 from config import DevelopmentConfig app.config.from_object(DevelopmentConfig) @app.route('/') def index(): print(app.config.get('PERMANENT_SESSION_LIFETIME')) return "index" if __name__ == '__main__': app.run(debug=True)
2. 切换配置
- 虽然封装了多套配置, 但需要 修改代码才能切换配置, 这种方式并不利于开发和测试
- Flask提供了切换配置的更好方案, 需要进行以下两步:
- 定义工厂函数, 封装应用的创建过程
- 利用环境变量, 调用工厂函数, 指定配置并动态创建应用
2.1 定义工厂函数
- 定义工厂函数, 封装应用的创建过程
代码示例
- 在前一节
config.py
的基础上, 定义字典记录配置类型和配置子类之间的映射关系
# config.py from datetime import timedelta class BaseConfig: """配置基类 可以将相同的配置抽取到基类中, 减少重复代码""" # 定义和配置同名的类属性 PERMANENT_SESSION_LIFETIME = timedelta(days=7) class DevelopmentConfig(BaseConfig): """开发环境""" SQL_URL = '127.0.0.1:3306/test1' # 数据库地址 class ProductionConfig(BaseConfig): """生产环境""" SQL_URL = '222.10.15:3306/users' # 数据库地址 # 定义字典来记录 配置类型 和 配置子类 之间的映射关系 config_dict = { 'dev': DevelopmentConfig, 'pro': ProductionConfig }
- 在主文件
main.py
中, 定义工厂函数封装应用的创建过程, 并通过参数指定应用对应的配置类型
from flask import Flask, current_app, Config from config import config_dict # 工厂函数: 根据参数需求, 内部封装对象的创建过程 def create_app(config_type): """封装应用的创建过程""" # 创建应用 flask_app = Flask(__name__) # 根据配置类型取出对应的配置子类 config_class = config_dict[config_type] # 加载普通配置 flask_app.config.from_object(config_class) return flask_app # 创建应用对象 app = create_app('dev') @app.route("/") def index(): print(app.config.get('SQL_URL')) return "index" if __name__ == '__main__': app.run()
2.2 动态创建应用
- 通过代码调用函数
create_app('dev')
创建应用, 仍然在代码中写死了 配置类型dev
- FLASK提供的环境变量
FLASK_APP
允许 以调用函数的形式动态创建应用- 格式:
FLASK_APP="应用所在模块:工厂函数(参数)"
- 格式:
$ export FLASK_APP="main:create_app('dev')" # 设置环境变量, 通过调用函数 设置配置并动态创建Flask应用 $ flask run # 运行web程序
注意: 如果动态创建应用, 通过 app = create_app('dev')
代码生成的Flask应用将会失效
- 需要使用
app
的时候, 可以使用current_app
来代替 (只能在请求范围中使用) - 将无法通过
app.route()
来定义路由, 但是 蓝图定义路由仍然有效
代码示例
from flask import Flask, current_app from config import config_dict def create_app(config_type): """封装应用的创建过程""" flask_app = Flask(__name__) config_class = config_dict[config_type] flask_app.config.from_object(config_class) # 由于动态创建应用(app失效), 不能通过app.route定义路由 # 添加路由规则 (实际开发中使用较少, 以蓝图定义路由为主) flask_app.add_url_rule('/', index.__name__, index) # 注册蓝图对象 蓝图可以正常使用 # from home import home_blu # flask_app.register_blueprint(home_blu) return flask_app # 定义视图函数, 不添加app.route()装饰器, 通过 添加路由规则 的方式手动定义路由 def index(): print(current_app.config.get('SQL_URL')) return "index" # app = create_app('dev') # app无效 # @app.route("/") # app无效 # def index(): # print(app.config.get('SQL_URL')) # return "index" # if __name__ == '__main__': # app.run() # app失效
3. 加载隐私配置
- 对于线上项目, 隐私配置 直接写在项目的配置文件中, 会 增加数据泄露的风险
- FLASK提供了 从环境变量中加载配置 的方案, 可用于加载隐私配置
-
- 该方案允许 通过环境变量指定配置文件的路径, 且 路径允许在项目目录以外
- 环境变量格式:
export 环境变量名="隐私配置的文件路径"
代码示例
- 在项目目录外 创建隐私配置文件
secret_config.py
, 并以全局变量形式设置隐私配置
# secret_config.py SECRET_KEY = 'heima123' # 隐私配置
- 主文件
main.py
通过环境变量方式来加载隐私配置
# main.py from datetime import timedelta from flask import Flask app = Flask(__name__) # 从环境变量中加载配置 # 优点: 可以保护隐私配置 export ENV_CONFIG="隐私配置的文件路径" app.config.from_envvar('ENV_CONFIG') @app.route('/') def index(): print(app.config.get('SECRET_KEY')) return "index" # if __name__ == '__main__': # app.run(debug=True)
- 环境变量&终端命令 启动程序
$ export FLASK_APP="main" # 设置内置环境变量 $ export ENV_CONFIG="/xx/secret_config.py" # 设置隐私配置对应的环境变量 $ flask run # 启动web程序
实际开发中的方案
- 开发阶段, 只加载普通配置
- 生产阶段, 先加载普通配置, 再通过环境变量的方式加载项目以外的隐私配置并覆盖原有配置
代码示例
def create_app(config_type): """封装应用的创建过程""" # 创建应用 flask_app = Flask(__name__) # 根据配置类型取出对应的配置子类 config_class = config_dict[config_type] # 先加载普通配置 flask_app.config.from_object(config_class) # 再加载隐私配置 silent=True, 配置加载失败也不报错 flask_app.config.from_envvar('ENV_CONFIG', silent=True) return flask_app
- 加载配置时, 设置参数
silent=True
, 则配置加载失败也不会报错