不能直接在settings.py里写死DATABASE_URL,因硬编码会导致多环境共用同一数据库,引发数据误操作;应通过os.environ或django-environ安全读取环境变量,并在文件顶部调用read_env()确保加载时机正确。

为什么不能直接在 settings.py 里写死 DATABASE_URL?
硬编码环境配置会导致本地调试、测试、生产共用同一套数据库,轻则连错库清空测试数据,重则误操作上线库。Django 本身不强制多环境分离,但 os.environ 是最轻量、最可控的入口——它不依赖第三方包,且和 Linux/macOS/Windows 的原生环境变量机制完全对齐。
常见错误现象:django.core.exceptions.ImproperlyConfigured: Set the DATABASE_URL environment variable,这通常不是因为你没设变量,而是 os.environ.get("DATABASE_URL") 返回了 None,而你又没给默认值或没做判空处理。
- 必须在
settings.py开头就 importos,否则后续读取会报NameError -
os.environ.get("DEBUG", "False")返回的是字符串,不是布尔值,"False"转成 bool 仍是True,得手动转换:os.environ.get("DEBUG", "False").lower() == "true" - 敏感配置(如
SECRET_KEY)绝不能写进代码或 git,必须由部署环境注入
如何用 environ 模块安全解析 DATABASE_URL?
environ 是比裸用 os.environ 更稳妥的选择,它内置了 URL 解析逻辑,能自动拆解 postgres://user:pass@host:port/dbname 成字典,避免手写正则或字符串切分出错。
安装:pip install django-environ;使用前需初始化:env = environ.Env()。注意:它默认只读取 .env 文件,不读系统环境变量,除非显式调用 environ.Env.read_env()。
立即学习“Python免费学习笔记(深入)”;
-
environ.Env.read_env()应放在settings.py最顶部,在DATABASES配置之前执行 - 若同时存在系统变量和
.env,系统变量优先级更高(可被覆盖),适合本地开发用.env,CI/CD 用 CI 平台变量 -
env.db("DATABASE_URL")返回标准 DjangoDATABASES字典结构,直接赋值即可:DATABASES = {"default": env.db("DATABASE_URL")} - 不推荐在
.env里写密码明文,尤其不要提交到 git;可用export DATABASE_URL="postgres://$DB_USER:$DB_PASS@localhost/mydb"在 shell 中组合
DEBUG 和 ALLOWED_HOSTS 怎么随环境自动切换?
这两个配置最容易因环境错配导致线上 500 或白屏。DEBUG=True 时 ALLOWED_HOSTS 被忽略,但一旦关掉 DEBUG,Django 会严格校验 Host header,填错直接 400。
典型做法是按 ENVIRONMENT 变量分流:env.str("ENVIRONMENT", default="development"),再用 if 分支控制:
ENVIRONMENT = env.str("ENVIRONMENT", default="development")
DEBUG = ENVIRONMENT == "development"
ALLOWED_HOSTS = ["localhost", "127.0.0.1"] if DEBUG else ["myapp.com", "www.myapp.com"]
-
env.str()第二个参数是默认值,避免 key 不存在时报 KeyError - 生产环境务必把
ALLOWED_HOSTS设为具体域名,不能用["*"](Django 会拒绝启动) - 如果用 Nginx 反向代理,还要加 Nginx 的内网 IP(如
"172.17.0.1"),否则可能因 Host header 被篡改而 400 -
SECURE_SSL_REDIRECT = not DEBUG这类衍生配置也建议统一基于DEBUG控制,减少遗漏
为什么 manage.py runserver 不读 .env?
因为 django-environ 默认只在 read_env() 被调用时加载 .env,而很多项目把这行漏写了,或写在了 if DEBUG: 块里——结果生产环境跑 python manage.py migrate 时根本没读到变量,报 KeyError。
- 确保
environ.Env.read_env()在settings.py文件顶部、任何配置读取之前执行 -
.env文件路径默认是BASE_DIR / ".env",如果放别处(如项目根目录外),要传参:environ.Env.read_env(BASE_DIR / ".." / ".env") - Git 必须忽略
.env:echo ".env" >> .gitignore,否则密钥泄露风险极高 - CI/CD 流水线中(如 GitHub Actions),应通过 secrets 注入变量,而不是上传
.env文件
.env 文件的优先级关系,以及 DEBUG 对其他安全配置的连锁影响。


















