Files
JobRadar/docs/lessons/01_Agent工程基线/1_1_Django项目配置与开发生产环境拆分

第1课:Django项目配置与开发/生产环境拆分

本课目标

完成本课后,你将能够:

  1. 解释Django设置模块(settings module)如何被加载。
  2. 将单一settings.py拆成公共、开发和生产三套配置。
  3. 使用DJANGO_SETTINGS_MODULE选择运行环境。
  4. 将生产密钥和域名移出Git仓库。
  5. 使用Django部署检查发现危险配置。

本课只学习配置拆分,不接入PostgreSQL、Celery或Agents SDK。

前置知识

  • 能运行python manage.py check和python manage.py runserver。
  • 理解Python模块和import。
  • 了解Spring Boot的Profile和application-{profile}.yml。

在JobRadar架构中的位置

JobRadar最终部署到公网,并需要数据库密码、模型API Key、招聘网站凭据等敏感配置。如果开发与生产共用一个settings.py,很容易出现以下问题:

  • 将开发环境的DEBUG = True带到公网。
  • 将生产密钥提交到Git。
  • 本地SQLite和生产PostgreSQL配置互相覆盖。
  • 本地地址、正式域名和HTTPS策略混在一起。
  • Agent运行时读取了错误的模型或密钥。

因此,安全配置是用户系统和Agent功能之前的工程基线。

核心原理

1. settings本质上是Python模块

Django设置不是特殊配置格式,而是包含模块级变量的Python模块。例如:

DEBUG = False
ALLOWED_HOSTS = ["jobradar.example.com"]

Django启动时读取DJANGO_SETTINGS_MODULE,然后导入该变量指定的Python模块:

JobRadar.settings.development
JobRadar.settings.production

点号是Python包路径,不是文件系统斜杠。

2. 公共配置与环境差异分离

本课采用三层结构:

JobRadar/
└── settings/
    ├── __init__.py
    ├── base.py
    ├── development.py
    └── production.py
  • base.py:应用、Middleware、模板、国际化等公共配置。
  • development.py:开发密钥、DEBUG = True和本地地址。
  • production.py:生产密钥、正式域名、HTTPS和安全Cookie。

development.py和production.py通过from .base import *继承公共配置。这种星号导入在普通业务代码中不推荐,但Django分层settings是一个边界明确的配置场景。

3. 与Spring Boot Profile对照

Spring Boot Django本课方案
application.yml settings/base.py
application-dev.yml settings/development.py
application-prod.yml settings/production.py
spring.profiles.active=dev DJANGO_SETTINGS_MODULE=JobRadar.settings.development
${DB_PASSWORD} os.environ["DB_PASSWORD"]
@Profile控制Bean Django通常在settings中切换组件配置

最大的区别是:Spring配置主要是YAML/Properties,Django settings本身就是Python代码。它更灵活,也意味着不能在里面随意写复杂业务逻辑。

完整参考代码

参考目录位于本课的reference/中:

reference/
├── settings/
│   ├── __init__.py
│   ├── base.py
│   ├── development.py
│   └── production.py
├── manage.py
├── asgi.py
└── wsgi.py

这些文件用于阅读和手动输入,不能直接覆盖当前项目。你需要理解每一处路径变化后,再把对应结构写入项目。

关键代码解析

BASE_DIR为什么多一个parent

原始settings.py位于:

JobRadar/settings.py

拆分后的base.py位于:

JobRadar/settings/base.py

文件多进入了一层settings目录,因此项目根目录改为:

BASE_DIR = Path(__file__).resolve().parent.parent.parent

如果仍使用两个parent,SQLite和模板目录都会指向错误位置。

为什么生产配置使用os.environ[名称]

SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]

方括号读取在变量缺失时立即抛出KeyError,让生产进程启动失败。相比提供一个不安全默认值,这种“快速失败”(fail fast)更安全。

开发配置可以使用明确标记为仅限本地的默认密钥,但生产配置绝不能提供默认生产密钥。

为什么入口的默认环境不同

  • manage.py默认开发配置,方便本地运行。
  • asgi.py和wsgi.py默认生产配置,降低部署时误启用开发设置的风险。
  • 命令行仍可通过--settings显式覆盖,便于检查两个环境。

手动实现步骤

  1. 在JobRadar包内创建settings目录及__init__.py。
  2. 参考base.py移动原settings.py的公共配置,并修正BASE_DIR。
  3. 编写development.py和production.py。
  4. 修改项目根目录的manage.py,默认指向开发配置。
  5. 修改JobRadar/asgi.py和JobRadar/wsgi.py,默认指向生产配置。
  6. 删除旧JobRadar/settings.py前,逐项确认内容已经迁移。
  7. 分别运行开发和生产配置检查。

不要直接复制整个reference目录覆盖项目,因为参考文件的层级和真实文件位置并不完全相同。

运行方法

检查开发配置

conda activate JobRadar
python manage.py check --settings=JobRadar.settings.development

预期结果:

System check identified no issues (0 silenced).

检查生产配置的缺失密钥保护

先确保当前PowerShell没有设置课程变量:

Remove-Item Env:DJANGO_SECRET_KEY -ErrorAction SilentlyContinue
python manage.py check --settings=JobRadar.settings.production

预期结果:命令失败,并明确提示缺少DJANGO_SECRET_KEY。这是安全保护生效,不是课程代码错误。

临时设置生产变量并检查

以下值只在当前PowerShell进程有效:

$env:DJANGO_SECRET_KEY = "仅用于本地检查的长随机字符串-请勿用于生产"
$env:DJANGO_ALLOWED_HOSTS = "jobradar.example.com"
$env:DJANGO_CSRF_TRUSTED_ORIGINS = "https://jobradar.example.com"
python manage.py check --settings=JobRadar.settings.production
python manage.py check --deploy --settings=JobRadar.settings.production

普通check应通过。check --deploy可能继续提示HSTS时长等部署建议;本课重点是能区分错误和安全告警,不要求为了消除告警而盲目开启尚未理解的配置。

检查完成后清理临时变量:

Remove-Item Env:DJANGO_SECRET_KEY
Remove-Item Env:DJANGO_ALLOWED_HOSTS
Remove-Item Env:DJANGO_CSRF_TRUSTED_ORIGINS

常见错误

错误1:No module named 'JobRadar.settings.development'

原因通常是:

  • 没有创建settings/__init__.py。
  • 包或模块名称拼错。
  • 旧settings.py仍存在,导致目录结构未正确调整。

错误2:SQLite文件出现在JobRadar/包内

原因是拆分后没有为BASE_DIR增加一层parent。

错误3:生产检查仍然使用开发配置

先查看命令是否传入:

--settings=JobRadar.settings.production

也可以运行:

python manage.py diffsettings --settings=JobRadar.settings.production

错误4:把生产密钥写入production.py

生产密钥必须由服务器部署环境注入。Git中的示例只能写变量名和虚假示例,不能包含真实值。

错误5:ALLOWED_HOSTS = ["*"]

星号允许任意Host,失去了Django主机头校验的主要意义。公网项目应填写明确域名;本地开发单独允许127.0.0.1和localhost。

课堂练习

练习要求见practice.py。该文件只有题目和验收标准,你的实际代码应写入JobRadar项目配置文件中。

自检清单

  • 能解释DJANGO_SETTINGS_MODULE的作用。
  • 能说明base.py中为什么使用三个parent。
  • 开发环境默认开启DEBUG,生产环境固定关闭。
  • 生产环境缺少密钥时会快速失败。
  • 生产域名和CSRF可信来源来自外部配置。
  • ASGI/WSGI默认指向生产配置。
  • Git差异中没有真实密钥。

验收标准

  1. python manage.py check --settings=JobRadar.settings.development通过。
  2. 缺少DJANGO_SECRET_KEY时,生产配置检查按预期失败。
  3. 临时提供生产变量后,普通生产配置检查通过。
  4. python manage.py makemigrations --check --dry-run --settings=JobRadar.settings.development显示无遗漏迁移。
  5. git diff --check通过。
  6. git diff中没有真实密钥、Cookie或密码。
  7. 学习者能解释开发和生产入口为何采用不同默认settings。

本课小结

本课没有增加业务功能,但建立了公网Agent项目的安全配置基础。Django通过DJANGO_SETTINGS_MODULE选择一个Python配置模块;公共设置放入base.py,开发和生产只覆盖差异。生产环境应关闭DEBUG、限制域名、启用HTTPS相关设置,并在缺少密钥时拒绝启动。

完成手动实现并通过验收后,下一课进入“Django用户系统与用户数据归属”。