# 第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模块。例如: ```python DEBUG = False ALLOWED_HOSTS = ["jobradar.example.com"] ``` Django启动时读取`DJANGO_SETTINGS_MODULE`,然后导入该变量指定的Python模块: ```text JobRadar.settings.development JobRadar.settings.production ``` 点号是Python包路径,不是文件系统斜杠。 ### 2. 公共配置与环境差异分离 本课采用三层结构: ```text 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/`中: ```text reference/ ├── settings/ │ ├── __init__.py │ ├── base.py │ ├── development.py │ └── production.py ├── manage.py ├── asgi.py └── wsgi.py ``` 这些文件用于阅读和手动输入,不能直接覆盖当前项目。你需要理解每一处路径变化后,再把对应结构写入项目。 ## 关键代码解析 ### `BASE_DIR`为什么多一个`parent` 原始`settings.py`位于: ```text JobRadar/settings.py ``` 拆分后的`base.py`位于: ```text JobRadar/settings/base.py ``` 文件多进入了一层`settings`目录,因此项目根目录改为: ```python BASE_DIR = Path(__file__).resolve().parent.parent.parent ``` 如果仍使用两个`parent`,SQLite和模板目录都会指向错误位置。 ### 为什么生产配置使用`os.environ[名称]` ```python 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`目录覆盖项目,因为参考文件的层级和真实文件位置并不完全相同。 ## 运行方法 ### 检查开发配置 ```powershell conda activate JobRadar python manage.py check --settings=JobRadar.settings.development ``` 预期结果: ```text System check identified no issues (0 silenced). ``` ### 检查生产配置的缺失密钥保护 先确保当前PowerShell没有设置课程变量: ```powershell Remove-Item Env:DJANGO_SECRET_KEY -ErrorAction SilentlyContinue python manage.py check --settings=JobRadar.settings.production ``` 预期结果:命令失败,并明确提示缺少`DJANGO_SECRET_KEY`。这是安全保护生效,不是课程代码错误。 ### 临时设置生产变量并检查 以下值只在当前PowerShell进程有效: ```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时长等部署建议;本课重点是能区分错误和安全告警,不要求为了消除告警而盲目开启尚未理解的配置。 检查完成后清理临时变量: ```powershell 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:生产检查仍然使用开发配置 先查看命令是否传入: ```text --settings=JobRadar.settings.production ``` 也可以运行: ```powershell python manage.py diffsettings --settings=JobRadar.settings.production ``` ### 错误4:把生产密钥写入`production.py` 生产密钥必须由服务器部署环境注入。Git中的示例只能写变量名和虚假示例,不能包含真实值。 ### 错误5:`ALLOWED_HOSTS = ["*"]` 星号允许任意Host,失去了Django主机头校验的主要意义。公网项目应填写明确域名;本地开发单独允许`127.0.0.1`和`localhost`。 ## 课堂练习 练习要求见[practice.py](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用户系统与用户数据归属”。