Skip to content

环境配置与应用启动 ​

本站纵览 | 练习答案

开发、测试、生产共享安全默认值,只覆盖真正不同的部分:

python
# config/settings_prod.py
import os
from .settings import *

DEBUG = False
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
ALLOWED_HOSTS = os.environ["DJANGO_ALLOWED_HOSTS"].split(",")
bash
DJANGO_SETTINGS_MODULE=config.settings_prod python manage.py check --deploy
python manage.py diffsettings

深水边界 ​

settings 模块是 Python 代码,导入时副作用会影响所有管理命令。环境变量适合小型配置输入,但仍需类型转换、必填校验、轮换和负责人。AppConfig.ready() 可能被测试、命令和多个进程分别调用,不在这里启动常驻线程或执行数据库写入。

独立脚本若绕开管理命令,需要先设置 DJANGO_SETTINGS_MODULE 并调用 django.setup();优先把业务脚本写成 management command,让启动合同统一。

验收 ​

缺少生产密钥时启动立即失败;diffsettings 能解释环境差异;应用初始化不访问数据库和外网。

练习(先独立完成) ​

  1. 为 ALLOWED_HOSTS 过滤空字符串并拒绝空生产配置。
  2. 将一次性数据导入改成 management command。
  3. 写测试证明导入 tickets.apps 不产生数据库查询。

完成后查看练习答案。

深度加餐:配置模块要像纯函数一样可预测 ​

settings 是 Python 模块,导入时做了什么,会影响 runserver、测试、迁移和 worker 的所有命令。

先做一个可观察实验 ​

python
# config/settings_base.py
import os

def env_bool(name, default=False):
    value = os.getenv(name)
    if value is None:
        return default
    return value.lower() in {'1', 'true', 'yes'}

DEBUG = env_bool('DJANGO_DEBUG')
ALLOWED_HOSTS = [host.strip() for host in os.getenv('DJANGO_ALLOWED_HOSTS', '').split(',') if host.strip()]
if not DEBUG and not ALLOWED_HOSTS:
    raise RuntimeError('production ALLOWED_HOSTS is empty')

预期:开发环境可使用默认值;生产环境缺少 ALLOWED_HOSTS 时启动直接失败,而不是等第一条请求才报错。

原理下潜与工程边界 ​

把共享默认值、环境覆盖和启动校验分成三层;敏感值从环境或 secret manager 注入,非敏感值也要做类型转换。AppConfig.ready 可能被导入多次,适合注册信号,不适合启动线程或写数据库。

导入 settings 时调用 ORM 会造成循环导入和迁移阶段查询;测试 override_settings 只影响当前进程;多进程部署不能依赖模块级单例保存跨请求状态。

反例排错路线 ​

分别运行 check、check --deploy、diffsettings 和一条最小测试;用 print 或日志排查配置是最后手段,优先暴露最终计算出的非敏感配置快照。

练习加码(仍不提供答案) ​

加码:把一次性 CSV 导入改成 management command,支持 --dry-run,并证明导入 config.settings_prod 不会产生数据库查询。

验收时请补充:正常路径、权限或失败路径、以及一条能证明事务/资源/配置边界没有被绕过的测试。

继续查阅:Django 官方文档(外部资料已收录于证据账本) · Django 安全清单(外部资料已收录于证据账本)

课程合同:环境隔离与应用启动 ​

学习目标 ​

学完本篇,读者应能把「同一代码在开发、测试、生产 settings 下启动且不泄漏秘密」拆成输入、可信边界、Django 机制和可复查证据;同时能说明 Django 6.0 与 5.2 LTS 的差异不会改变业务不变量。

心智模型 ​

请求/数据输入 → 边界检查 → Django 核心机制 → 可观察输出 → 恢复动作。配置、数据库提交和外部副作用分别拥有自己的生命周期;没有证据的“应该可以”不算完成。

本地机制图 ​

环境隔离与应用启动机制图

图中的“输入”是不可信的 HTTP、表单、任务或配置;“边界”负责身份、格式、权限、大小、超时与版本;“机制”才是 URL、View、ORM、事务、缓存、Tasks 或 ASGI;“证据”是测试、响应、日志、查询计划和发布记录。

最小实验 ​

在全新虚拟环境中运行:

bash
python -m django --version
python manage.py check
python manage.py test

实验只验证一个机制:输入一条有效值,再输入一条空值、重复值或无权限值。每次实验都记录 Django 版本、数据库、命令和退出码。

完整场景 ​

把实验接到 tickets 工单流:请求携带用户身份和工单 ID,经过当前专题负责的边界,完成一次读或写,并留下响应状态、数据库变化、日志字段和清理动作。完整场景必须能第二次执行,或明确说明幂等键、事务回滚、缓存失效和任务重试策略。

运行输出 ​

成功路径应出现:

text
Django 6.0.x
System check identified no issues (0 silenced).
OK

失败路径要保留真实信号,例如 400(输入无效)、403(权限/CSRF)、404(资源不存在)、405(方法不允许)或数据库约束异常;不要把失败改写成含糊的 200。

失败边界 ​

至少验证:空输入、重复提交、匿名用户、越权对象、并发写入、下游不可用、超时和版本不兼容。记录“谁拒绝、何时拒绝、状态是否回滚、重试是否安全”。开发模式的 traceback 不得进入生产响应,缓存不得跨用户复用敏感结果。

原理与排错 ​

先确认版本和 settings,再用 manage.py check 定位启动问题;接着确认 URL/任务入口、输入解析和权限;最后检查 SQL、事务提交、响应和副作用。若结果异常,用最小复现打开 SQL/请求 ID/任务 ID 观测,沿「复现 → 缩小 → 观测 → 修复 → 回归」闭环,不靠重装依赖猜测。

练习(正文不泄答案) ​

  1. 为上述完整场景补一条正常路径和两条失败路径测试,并记录完整输出。
  2. 画出本篇机制图,标出身份 owner、数据提交点、缓存/任务副作用和恢复动作。
  3. 故意制造一次重复、越权或超时,说明应返回的状态、日志字段和是否可重试。
  4. 写一条 Django 5.2 LTS 兼容验收标准,再说明 Django 6.0 的新能力是否需要条件分支。

验收标准:命令可重复、输出可复查、正文没有练习答案;完成后再打开本阶段答案册。

答案册 ​

本阶段答案册提供参考实现、关键推理、失败边界和替代方案;先独立完成练习再对照。

下一篇 ​

下一篇是02-urls-views-templates/01-url-view-template,继续沿同一条输入—边界—机制—证据链前进。

用心记录每一步成长