数据库地址、API 密钥、调试开关——如果写死在代码里:换环境要改代码、密钥泄露风险、多人协作冲突。配置管理解决:同一份代码,在不同环境加载不同配置。
Flask 用 app.config 统一管理配置(一个类字典对象)。核心问题:配置从哪来、怎么按环境切换。
💡 关键直觉:配置是"应用的参数",环境是"参数集"。开发一套参数(debug 开、本地数据库)、生产一套(debug 关、线上数据库)——代码不变,换参数集即可。
from flask import Flask app = Flask(__name__) # 直接设置 app.config['SECRET_KEY'] = 'my-secret' app.config['DEBUG'] = True # 或 update app.config.update( SECRET_KEY='my-secret', SESSION_COOKIE_HTTPONLY=True, ) # 读取 print(app.config['SECRET_KEY']) print(app.config.get('DEBUG', False))
# config.py SECRET_KEY = 'dev-secret' DATABASE_URL = 'sqlite:///dev.db' # app.py app.config.from_object('config') # 从模块加载
from_object 把模块里的大写变量全部加载为配置。
# config.py import os class Config: """基础配置(所有环境共享)""" SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-secret') SESSION_COOKIE_HTTPONLY = True JSON_SORT_KEYS = False class DevelopmentConfig(Config): DEBUG = True DATABASE_URL = 'sqlite:///dev.db' class TestingConfig(Config): TESTING = True DATABASE_URL = 'sqlite:///test.db' class ProductionConfig(Config): DEBUG = False DATABASE_URL = os.environ.get('DATABASE_URL') SESSION_COOKIE_SECURE = True # 生产强制 HTTPS config = { 'development': DevelopmentConfig, 'testing': TestingConfig, 'production': ProductionConfig, 'default': DevelopmentConfig, }
# app.py def create_app(config_name=None): app = Flask(__name__) config_name = config_name or os.environ.get('FLASK_CONFIG', 'default') app.config.from_object(config[config_name]) return app app = create_app()
环境切换:
# 开发 export FLASK_CONFIG=development; python app.py # 生产 export FLASK_CONFIG=production DATABASE_URL=postgres://...; gunicorn app:app
默认值 < 配置文件 < 环境变量 < 代码显式设置
设计原则:敏感配置(密钥、密码)只从环境变量读,代码里只给开发默认值。这样密钥不提交到 git,生产环境通过环境变量注入。
⚠️ 常见坑:密钥提交进 git。开发用
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-secret'),生产必须通过环境变量注入真实密钥——别把真实密钥写进配置文件提交仓库。
import os from flask import Flask class DevConfig: DEBUG = True ENV_NAME = "开发环境" DATABASE_URL = "sqlite:///dev.db" class ProdConfig: DEBUG = False ENV_NAME = "生产环境" DATABASE_URL = os.environ.get('DATABASE_URL', "sqlite:///prod.db") config_map = {"dev": DevConfig, "prod": ProdConfig} app = Flask(__name__) env = os.environ.get('FLASK_ENV', 'dev') app.config.from_object(config_map[env]) @app.route('/') def index(): return f"当前环境: {app.config['ENV_NAME']},数据库: {app.config['DATABASE_URL']}" if __name__ == '__main__': app.run(debug=app.config['DEBUG'])
设置 FLASK_ENV=dev 或 FLASK_ENV=prod 运行,观察页面变化——同一份代码,两个环境的配置不同。
用 python-dotenv 管理本地环境变量(.env 文件不入 git):
# 安装: pip install python-dotenv from dotenv import load_dotenv load_dotenv() # 加载 .env 文件到环境变量 import os SECRET_KEY = os.environ.get('SECRET_KEY') DATABASE_URL = os.environ.get('DATABASE_URL')
# .env(不入 git) SECRET_KEY=xxxxx DATABASE_URL=postgres://user:pass@localhost/db
.env 的价值:本地开发方便(一个文件管理所有环境变量);.gitignore 排除它,密钥不进仓库。生产环境用真正的环境变量或密钥管理系统。
问:为什么配置用大写变量?
Flask 的 from_object 只加载大写变量(约定优于配置)——避免把模块里的函数、小写变量误当配置。
问:测试时怎么改配置?app.config.update(TESTING=True) 或直接改 app.config['DATABASE_URL']——测试 fixture 里灵活覆盖。
问:配置可以热更新吗?
运行时改 app.config 立即生效(如改 DEBUG)。但生产建议"重启生效"(配置在启动时加载),避免运行时改配置引发混乱。
问:一个应用能加载多个配置来源吗?
能,按优先级叠加:默认值 < 配置文件 < 环境变量 < 代码显式设置。from_object 可以多次调用,后调覆盖先调。
配置让应用"换环境就跑",但"Flask 内部怎么保证线程安全"还没讲。下一节看上下文(Context)——请求上下文与应用上下文,Flask 的底层机制。
配置管理的核心矛盾是"安全、灵活、可复现"三者兼顾。几个进阶模式帮你应对真实场景。
第一,.env 文件与 python-dotenv。 环境变量写在命令行里又长又难管理,业界标准做法是用 .env 文件(键值对格式)配合 python-dotenv 自动加载:
# .env(不入 Git) SECRET_KEY=xxxx DATABASE_URL=postgresql://... MAIL_PASSWORD=xxxx # 加载 from dotenv import load_dotenv load_dotenv() # 自动读取项目根目录 .env
关键纪律:.env 必须加入 .gitignore(里面有密钥);仓库里放一个 .env.example 模板(只有键名没有真实值),新同事复制改值即可。
第二,配置的"三个来源 + 优先级"。完整的配置读取顺序应该是:代码默认值 < 配置文件 < 环境变量。代码默认值保证"开箱能跑";配置文件(Config 类)按环境选型;环境变量覆盖敏感项与部署差异。永远让环境变量有最高优先级,这样部署时不用改代码。
第三,敏感配置的"零信任"原则。SECRET_KEY、数据库密码、API 密钥——默认假设"会被泄露",所以:不入 Git、定期轮换、按环境隔离(开发/测试/生产用不同密钥)、权限最小化(只给需要的服务)。企业环境还常用密钥管理服务(云厂商 KMS/Secrets Manager)统一管理。
第四,配置的验证。配置错了比代码错了更难发现(应用可能"带病运行")。建议在工厂函数里做启动时校验:SECRET_KEY 是否缺失、数据库能否连接、必要配置是否为空——不满足就直接报错退出,fail fast(快速失败)而不是带病上线。
第五,多环境配置的组织。Config 基类放公共配置,DevelopmentConfig/TestingConfig/ProductionConfig 继承并覆写差异项,config_map 字典映射环境名到类。工厂函数 create_app(config_name) 按需选型——这套模式在第三章、第四章会反复出现,是 Flask 项目的标准答案。
第六,配置热更新。生产环境改配置是否需要重启?对于大多数配置,重启即可(部署流程里自带重启);对于需要热更新的场景(如功能开关),把开关放进数据库或 Redis,配置只放"连接参数"——这是"动态配置"的进阶思路,本章先理解静态配置,动态配置在需要时再深入研究。