理想情况下,只需要一个config文件
在简单的项目里,往往只需要一个配置文件就可以了。
配置文件写成yaml格式,然后使用yaml.load()就可以简单的使用
common.yaml文件
authorize:
{ token: justtoken,
expire_time: 1200,
reset_password_expire_time: 2400
}
date_format: '%Y-%m-%d %H:%M:%S'
使用 python 读取
import yaml
config_file = open('common.yml')
CONF = yaml.safe_load(config_file)
print(CONF)
执行结果
{'authorize': {'token': 'justtoken', 'expire_time': 1200, 'reset_password_expire_time': 2400}, 'date_format': '%Y-%m-%d %H:%M:%S'}
生产环境的分离伴随着config的拆分
然而在实际的项目执行过程中,我们会把代码环境区分为正式环境和开发环境,与此同时就有
- 正式环境数据库
- 开发环境数据库
显然,一个config文件已经无法完成区分,所以需要两份config文件
dev.yml
db:
{
SQLALCHEMY_DATABASE_URI: "mysql+pymysql://admin@localhost:3306/test?charset=utf8mb4"
}
prod.yml
db:
{
SQLALCHEMY_DATABASE_URI: "mysql+pymysql://admin@xxx:3306/prod?charset=utf8mb4"
}
再使用一个环境变量来决定使用哪一个config文件
import os
import yaml
env = os.environ.get('env', 'dev')
if env == 'prod':
config_file = open('prod.yml')
CONF = yaml.safe_load(config_file)
elif env == 'dev':
config_file = open('dev.yml')
CONF = yaml.safe_load(config_file)
else:
raise EnvironmentError('Environment error')
print(CONF)
注:
-
使用 export 命令设置环境变量
export env=“prod”
-
如果没有设置环境变量,则默认为dev环境
env = os.environ.get(‘env’, ‘dev’)
执行结果
当环境为dev时候
{'db': {'SQLALCHEMY_DATABASE_URI': 'mysql+pymysql://admin@localhost:3306/test?charset=utf8mb4'}}
当环境为prod时候
{'db': {'SQLALCHEMY_DATABASE_URI': 'mysql+pymysql://admin@xxx:3306/prod?charset=utf8mb4'}}
更进一步,敏感信息需要在config文件里面隐藏
像数据库密码,账号token之类的敏感信息是不应该写在代码里面的,别人一看得到了你的代码,就得到了你的账号和数据库的访问权。所以需要将敏感信息独立出来,不写在代码里面
-
把敏感信息从config文件里面拿掉
-
将敏感信息写在环境变量里面
-
代码里面将敏感信息读取出来
def load_env_outside():
env_conf = dict()
env_conf[‘database_password’] = os.environ.get(‘database_password’)
return env_conf -
和现有的config做合并
def merge_conf(base, to_be_merged):
for i in to_be_merged.keys():
base[i] = to_be_merged[i]
return baseif env == 'dev': dev_conf = load_env('dev.yml') elif env == 'prod': prod_conf = load_env('prod.yml') env_outside = load_env_outside() CONF = merge_conf(prod_conf, env_outside) else: raise EnvironmentError('Environment error') print(CONF)
执行结果为
{'db': {'SQLALCHEMY_DATABASE_URI': 'mysql+pymysql://admin@xxx:3306/prod?charset=utf8mb4'}, 'database_password': 'hello'}
注:
- 执行环境为prod
- 往往测试环境是可以直接写代码在config里面的,但是prod不行,所以测试环境没有做合并
(optional)减少出错的可能性,把公共部分的配置文件分离出来
程序在开发的时候,改了一个dev的config,但是没有改prod的config,最后上线的时候出了bug。这时候把公共的config单独提取出来,可以避免一部分这个问题
- 提取共有config
举个例子 common.yml
authorize:
{ token: justtoken,
expire_time: 1200,
reset_password_expire_time: 2400
}
date_format: '%Y-%m-%d %H:%M:%S'
-
做合并
import os import yaml env = os.environ.get('env', 'dev') def load_env(env_file_name): file = open(os.path.join(os.path.dirname(__file__), env_file_name), 'r', encoding='utf-8') cfg = yaml.safe_load(file) return cfg def merge_conf(base, to_be_merged): for i in to_be_merged.keys(): base[i] = to_be_merged[i] return base def load_env_outside(): env_conf = dict() env_conf['database_password'] = os.environ.get('database_password') return env_conf CONF = load_env('common.yml') if env == 'dev': dev_conf = load_env('dev.yml') CONF = merge_conf(CONF, dev_conf) elif env == 'prod': prod_conf = load_env('prod.yml') CONF = merge_conf(CONF, prod_conf) env_outside = load_env_outside() CONF = merge_conf(CONF, env_outside) else: raise EnvironmentError('Environment error') print(CONF)
执行结果
{'authorize': {'token': 'justtoken', 'expire_time': 1200, 'reset_password_expire_time': 2400}, 'date_format': '%Y-%m-%d %H:%M:%S', 'db': {'SQLALCHEMY_DATABASE_URI': 'mysql+pymysql://admin@xxx:3306/prod?charset=utf8mb4'}, 'database_password': 'hello'}