CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
Django 实战入门/课时/项目结构
RawBlame
课时目录12 节

Django 实战入门

  1. 01Django 概览
  2. 02项目结构
  3. 03URL 路由
  4. 04视图层
  5. 05模型与 ORM
  6. 06查询与优化
  7. 07模板 DTL
  8. 08Admin 与认证
  9. 09表单与安全
  10. 10DRF 与异步任务
  11. 11测试与部署
  12. 12综合练习

项目结构

settings/urls/manage 与请求流。

30 分钟

项目结构

这一课你将能做到

  1. 用 startproject + startapp 创建标准的 Django 项目骨架,并解释每个文件的作用
  2. 正确区分「项目(project)」和「应用(app)」,并知道何时该拆 app
  3. 修改 settings.py 的关键配置(INSTALLED_APPS、DATABASES、TEMPLATES、静态文件),并理解配置加载顺序

为什么要学

Django 项目的目录结构和 Spring Boot 的 Maven 结构一样,是「约定优于配置」的体现。你打开任何一份生产级 Django 代码,目录骨架 95% 一致。看懂结构就拿到了读 Django 代码的钥匙。

和 Spring Boot 对照:Spring Boot 一个项目就是一个可执行 jar,用包(package)划分业务模块;Django 一个项目下挂多个 app,每个 app 是一个独立可复用的 Python 包,有自己的 models/views/urls/templates。理解这个差异,是理解 Django 模块化设计的关键。

先建立图像

标准 Django 项目目录(项目名 mysite,包含一个 app blog):

mysite/                  ← 项目根(你随便起名)
├── manage.py            ← 命令行入口
├── mysite/              ← 项目配置包(项目名同名)
│   ├── __init__.py
│   ├── settings.py      ← 全局配置
│   ├── urls.py          ← 根 URL 路由
│   ├── asgi.py          ← ASGI 入口(异步部署用)
│   └── wsgi.py          ← WSGI 入口(同步部署用)
├── blog/                ← 应用(可复用的业务模块)
│   ├── migrations/      ← 数据库迁移文件
│   ├── admin.py         ← Admin 注册
│   ├── apps.py          ← app 配置
│   ├── models.py        ← 数据模型
│   ├── tests.py         ← 测试
│   ├── urls.py          ← app 自己的路由(可选)
│   └── views.py         ← 视图
├── templates/           ← 项目级模板(可选)
├── static/              ← 项目级静态文件(可选)
└── db.sqlite3           ← 默认 SQLite 数据库

一次请求的路径:

浏览器 → WSGI → settings.ROOT_URLCONF(mysite/urls.py)
              → 匹配 path("blog/", include("blog.urls"))
              → blog/urls.py → blog/views.py::post_detail
              → blog/models.py (查数据库)
              → templates/blog/post_detail.html (渲染)
              → 返回 HTML

跟着做

步骤 1:创建项目

django-admin startproject mysite .
cd mysite

注意末尾的 .——让 Django 在当前目录生成项目,避免多套一层同名目录。

步骤 2:创建第一个 app

python manage.py startapp blog

执行后多了 blog/ 目录。app 的精髓是「可复用」——理论上你可以把这个 blog/ 拷到别的 Django 项目里直接用。

步骤 3:注册 app 到项目

打开 mysite/settings.py,在 INSTALLED_APPS 末尾加上:

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "blog",  # ← 新增
]

这一步常被初学者漏掉。不注册,Django 不会扫描这个 app 的 models.py,迁移时找不到模型。

步骤 4:看一眼关键配置

settings.py 里几个必须知道的字段:

# 安全相关
SECRET_KEY = "django-insecure-..."   # 会话/CSRF 签名密钥,生产环境要从环境变量读
DEBUG = True                          # 开发模式;生产必须 False
ALLOWED_HOSTS = []                    # 允许访问的域名/IP,DEBUG=False 时必须配置

# 应用与中间件
INSTALLED_APPS = [...]
MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",       # CSRF 防护
    "django.contrib.auth.middleware.AuthenticationMiddleware",  # 注入 request.user
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

# URL 入口
ROOT_URLCONF = "mysite.urls"

# 模板
TEMPLATES = [{
    "BACKEND": "django.template.backends.django.DjangoTemplates",
    "DIRS": [BASE_DIR / "templates"],   # 项目级模板目录
    "APP_DIRS": True,                   # 自动扫描每个 app 下的 templates/
    ...
}]

# 数据库
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
    }
}

# 静态文件
STATIC_URL = "static/"

步骤 5:用 app 拆 URL

mysite/urls.py:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("blog/", include("blog.urls")),  # 把 /blog/ 前缀转发给 blog app
]

新建 blog/urls.py:

from django.urls import path
from . import views

app_name = "blog"   # 命名空间,反查 URL 时用 blog:post_list

urlpatterns = [
    path("", views.post_list, name="post_list"),
    path("<int:pk>/", views.post_detail, name="post_detail"),
]

blog/views.py:

from django.http import HttpResponse


def post_list(request):
    return HttpResponse("文章列表")


def post_detail(request, pk):
    return HttpResponse(f"文章详情 id={pk}")

启动后访问 /blog/ 和 /blog/42/ 都能命中对应视图。

步骤 6:理解 manage.py 干了什么

#!/usr/bin/env python
import os
import sys


def main():
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError("...") from exc
    execute_from_command_line(sys.argv)


if __name__ == "__main__":
    main()

核心就一件事:设置 DJANGO_SETTINGS_MODULE 环境变量,告诉 Django 去哪读配置,然后把命令行交给 Django 内核。

讲清楚要点

  1. 项目 vs 应用:项目是网站整体配置+入口;app 是可复用功能模块。一个项目可挂 N 个 app。判断标准:能不能拷到别的项目直接用?能→app。
  2. INSTALLED_APPS 是注册表:Django 启动时按顺序加载这些 app,扫描它们的 models、admin、signals。漏注册 = app 没接入。
  3. BASE_DIR 是路径基准:settings.py 顶部定义的 Path(__file__).resolve().parent.parent,所有路径配置都基于它,避免硬编码绝对路径。
  4. 配置分层思想:生产项目常把 settings 拆成 base.py / dev.py / prod.py,或读环境变量。开发期单文件够用,但要知道有这套玩法。第 11 课会展开。
  5. include() 是路由分发器:项目根 urls.py 不该写具体业务路由,只该 include 各 app 的 urls。这样 app 自治,可插拔。
  6. wsgi.py vs asgi.py:wsgi 是同步部署入口(Gunicorn、uWSGI);asgi 是异步入口(Uvicorn、Daphne),支持 WebSocket。新项目两个文件都有,按部署方式选。

你可能会懵的地方

  • 什么时候拆 app? 功能边界清晰就拆:用户/订单/文章/评论各一个 app。别一上来拆 10 个,也别全堆在一个 app 里。经验法则:一个 app 的 models.py 超过 500 行就该考虑拆。

  • __init__.py 能删吗? 不能。它把目录标记成 Python 包,删了 import 会失败。Python 3.3+ 支持「命名空间包」不带它也能跑,但 Django 默认约定还是带上。

  • mysite/mysite/ 同名目录是干嘛的? 外层是项目容器,内层是项目「配置包」。改名内层不影响,只要 settings.py 里的 ROOT_URLCONF 和 WSGI_APPLICATION 指向正确即可。

  • app 下的 urls.py 是必须的吗? 不是。你可以把所有路由都写在项目根 urls.py 里。但工程上推荐每个 app 自带 urls,根 urls 只做 include。

  • apps.py 里那个类有什么用? 是 app 的「配置类」。可以重写 ready() 方法在 app 加载完成时执行初始化代码(比如注册信号)。普通情况不用动。

错法对照

错法问题正解
改了 models.py 没把 app 加进 INSTALLED_APPSmakemigrations 检测不到创建 app 后立即注册
在根 urls.py 写一堆业务路由根路由膨胀、app 无法复用用 include() 分发到 app
BASE_DIR 写死绝对路径换机器就崩始终用 BASE_DIR / "xxx"
DEBUG = True 直接上生产报错页泄露敏感信息生产必须 DEBUG=False 并配 ALLOWED_HOSTS
把密钥硬编码在 settings.py 并提交到 git安全事故os.environ.get("SECRET_KEY") 从环境变量读

卡点急救

  1. ModuleNotFoundError: No module named 'blog':startapp 之后没把 blog 加入 INSTALLED_APPS,或者运行 manage.py 时工作目录不对(必须在项目根)。
  2. 访问 /blog/ 返回 404,但路由明明配了:根 urls.py 里忘了 include("blog.urls"),或 app_name 与 namespace 冲突。
  3. ImproperlyConfigured: The SECRET_KEY setting must not be empty:环境变量没设或没读到。检查 .env 是否被加载,或临时在 settings.py 里写个默认值。

面试常问

  • Django 项目和 app 的区别?什么场景拆 app? 项目是站点级容器(配置、URL 入口、WSGI/ASGI);app 是可复用的业务模块(用户、订单、文章)。当一个功能模块可以独立打包复用,或团队多人协作需要明确边界时,应该拆 app。

  • Django 启动时 settings.py 的加载顺序是怎样的? manage.py 设 DJANGO_SETTINGS_MODULE → Django 启动时 import 该模块 → 模块顶部定义 BASE_DIR 等基础常量 → INSTALLED_APPS 逐个加载,触发各 app 的 apps.py::AppConfig.ready() → 路由懒加载(首次请求时编译)。

  • 生产环境 SECRET_KEY 怎么管? 不能进 git。常见做法:环境变量(os.environ.get)、密钥管理服务(Vault、AWS Secrets Manager)、CI/CD 注入。开发可用 django-insecure- 前缀的随机串,生产必须独立生成且保密。

自测三问

  1. 为什么 Django 要把项目「配置包」和应用「app」分开?
  2. INSTALLED_APPS 漏写一个 app 会发生什么?
  3. include() 在 urls.py 里的作用?为什么推荐根 urls 只做 include?

小结一句话

Django 项目 = 一份配置 + 一组可插拔 app;理解 settings.py 和 urls.py 的角色分工,是写大型 Django 应用的地基。

延伸

  • Django 官方文档 - 项目和应用
  • 下一课:URL 路由——path converters、命名 URL、reverse 反查。
加载本节练习…
← 上一课Django 概览下一课 →URL 路由