不能用 os.environ.get() 硬编码读取,因未判空易抛 keyerror、字符串默认值导致类型误判(如 "false" 转布尔为 true)、手动转换类型易错且不可复用。

直接把 SECRET_KEY、数据库密码、API 密钥写进 settings.py 是最常见也最危险的做法——它们会随代码一起被提交到 Git,一旦仓库泄露,整个系统就裸奔了。
为什么不能用 os.environ.get() 硬编码读取?
很多人在 settings.py 里写 os.environ.get('DB_PASSWORD'),看似“用了环境变量”,但实际埋了三个坑:
- 没设默认值或没判空,遇到变量缺失直接抛
KeyError或ImproperlyConfigured -
os.environ.get("DEBUG", "False")返回的是字符串"False",转成布尔仍是True,导致生产环境意外开启调试模式 - 所有类型都得手动转换:
int、bool、逗号分隔的列表(如ALLOWED_HOSTS)全靠自己split()和strip(),容易出错且不可复用
python-decouple 是最轻量又可靠的方案
它专为 Django 设计,核心优势是「类型即配置」:你在 config() 里声明要什么类型,它就自动帮你转,失败时给清晰报错。不用自己写一堆 if/else 判空和类型转换逻辑。
- 安装:
pip install python-decouple - 项目根目录建
.env文件(记得加进.gitignore):SECRET_KEY=django-insecure-xxx<br>DEBUG=True<br>DATABASE_URL=postgres://user:pass@localhost/dbname<br>ALLOWED_HOSTS=localhost,127.0.0.1
-
settings.py开头读取:from decouple import config<br><br>SECRET_KEY = config('SECRET_KEY')<br>DEBUG = config('DEBUG', default=False, cast=bool)<br>ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='127.0.0.1', cast=lambda v: [s.strip() for s in v.split(',')])
django-environ 更适合复杂 URL 类型解析
当你的 DATABASE_URL、CACHE_URL、EMAIL_URL 是完整 URL 格式时,django-environ 能自动拆解成字典,省去手写正则或字符串切分的麻烦。
- 安装:
pip install django-environ -
settings.py顶部初始化:import environ<br>env = environ.Env()<br>environ.Env.read_env() # 必须放最前面,且只调用一次
- 直接解析 URL:
DATABASES = {'default': env.db('DATABASE_URL')}它会自动识别postgres://、mysql://并填好ENGINE、NAME、USER等字段 - 注意:
env.db()不会 fallback 到os.environ,它只读.env和系统环境变量;如果想让 CI 环境变量覆盖.env,默认就支持(系统变量优先级更高)
密钥必须严格隔离,禁止复用 SECRET_KEY
有人图省事,拿 settings.SECRET_KEY 去生成数据库加密密钥,比如调 Fernet.generate_key_from_password() —— 这等于把门锁和保险柜钥匙焊死在一起。
-
SECRET_KEY是 Django 框架级密钥,用于 session、CSRF、重置链接签名等,暴露面广、生命周期长 - 数据库字段加密密钥(如
ENCRYPTION_KEY)应独立管理,通过os.environ.get('DJANGO_ENCRYPTION_KEY')单独注入 - 两者复用会导致轮换成本飙升:改一个就得同步改所有依赖它的模块,线上出问题概率翻倍
真正难的不是选哪个库,而是确保每个密钥都有明确归属、独立生命周期,并且从不以任何形式出现在日志、错误页或前端响应中。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











