Django + Vue电商项目第005讲:后端骨架|Django初始化、配置分层与DRF接入

本讲是M0里程碑的收官 。第4讲前端能跑,第5讲后端能跑,下一讲开始就是「业务代码」了。

⚠️ M0成就解锁 :跑通python manage.py runserver,浏览器访问/api/v1/health/返回{"status": "ok"}。

建议先 点赞 + 收藏 + 关注,配 settings 分层时随时回查。


一、为什么用Django而不是Flask

很多新人会问:

现在不都用FastAPI了吗?Django不老吗?

这个问题有四层回答。

第一层:教学曲线。

Django是「全家桶」------ORM、Admin、Auth、迁移、缓存、信号、中间件、国际化开箱即用。Flask 灵活但散装,你每做一个新模块都要选「这个项目目录该长什么样、这个ORM怎么用、这个Admin怎么搭」。

专栏如果用Flask,就会陷入选型疲劳。Django把这些决策提前做了,你只需要跟着学。

第二层:就业面。

打开招聘软件搜「Python后端」,Django出现频次远高于FastAPI。FastAPI是新趋势没错,但国内大部分存量系统是Django。学完能直接对接企业真实项目。

第三层:生态完整度。

Django的第三方包覆盖了你能想到的所有场景:

  • DRF(API)
  • SimpleJWT(鉴权)
  • Celery(异步)
  • channels(WebSocket)
  • Debug Toolbar(调试)
  • Django Admin(后台)
  • django-cors-headers(CORS)

FastAPI生态也在长,但很多场景需要自己拼。

第四层:性能不是短板。

Django引入ASGI异步视图 + async ORM,在I/O密集场景与FastAPI持平。后面我们会用Celery把CPU密集任务扔出主线程。

💡 什么时候选FastAPI ?

纯异步 + 高并发 + 微服务场景(比如物联网网关、实时数据流),FastAPI更合适。本专栏是电商B2C单体应用,Django更匹配。


二、创建工程

切到对应的特性分支:

bash 复制代码
cd ~/workspace/shopx
git switch develop
git pull
git switch -c feature/lecture-005-backend-scaffold

创建 Django 工程

在项目根目录创建backend/子目录作为后端代码根:

bash 复制代码
mkdir backend
cd backend

激活虚拟环境(第 2 讲建的):

bash 复制代码
source ../.venv/bin/activate
# Windows WSL: 同样命令
# 注意路径是 ../.venv 因为我们在 backend 子目录

💡 也可以把.venv/放在backend/内部,路径更短。但本专栏用monorepo,.venv/放根目录统一管理。

创建 Django 工程:

bash 复制代码
django-admin startproject shopx .

末尾的 . 很重要 ------它表示在当前目录(backend/)创建工程,而不是再嵌套一层shopx/shopx/。如果你忘了打点,后面路径会很乱。

生成的目录:

text 复制代码
backend/
├── manage.py           # 命令行入口
└── shopx/
    ├── __init__.py
    ├── asgi.py         # ASGI 入口(异步)
    ├── wsgi.py         # WSGI 入口(同步)
    ├── settings.py     # 配置文件(本讲要拆)
    └── urls.py         # 根路由

验证Django装好

bash 复制代码
python manage.py runserver
# Watching for file changes with StatReloader
# Starting development server at http://127.0.0.1:8000/
# Quit the server with CONTROL-C.

浏览器访问http://127.0.0.1:8000/,看到Django默认欢迎页(火箭图)。Ctrl+C关掉,我们继续改配置。


三、第一个App:health

Django的「App」是一个可独立复用的功能模块。商城后端最终会有11个app(users goods cart orders ...),但本讲只建一个最简的 health------用于探活接口。

创建health app

bash 复制代码
python manage.py startapp health

生成:

text 复制代码
health/
├── __init__.py
├── admin.py
├── apps.py
├── migrations/
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

注册到INSTALLED_APPS

打开shopx/settings.py,找到INSTALLED_APPS,加上:

python 复制代码
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 第三方
    'rest_framework',
    'corsheaders',
    # 本项目
    'health',
]

写第一个 APIView

编辑 health/views.py:

python 复制代码
from rest_framework.views import APIView
from rest_framework.response import Response


class HealthView(APIView):
    """健康检查接口,供前端、第 92 讲的 K8s 探针、第 100 讲的部署脚本使用。"""

    def get(self, request):
        return Response({
            "status": "ok",
            "service": "shopx",
            "version": "0.1.0",
        })

配 URL

新建 health/urls.py:

python 复制代码
from django.urls import path
from .views import HealthView

urlpatterns = [
    path('health/', HealthView.as_view(), name='health'),
]

编辑 shopx/urls.py(根路由):

python 复制代码
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('health.urls')),
]

注意:所有业务接口都挂在 /api/v1/ 下 。v1 是 API 版本号,第 80 讲会讲 API 版本管理的几种策略。


四、settings 分层(教学上的关键工程实践)

默认的 settings.py 是单文件,所有配置(数据库、邮件、缓存、第三方、调试)混在一起。生产级 Django 项目必须分层,否则换环境时改一堆地方容易出错。

拆分成 4 个文件

把 settings.py 删掉,新建 settings/ 目录:

bash 复制代码
rm shopx/settings.py
mkdir shopx/settings
touch shopx/settings/__init__.py

生成 4 个文件:

text 复制代码
shopx/
└── settings/
    ├── __init__.py
    ├── base.py      # 公共配置(所有环境共享)
    ├── dev.py       # 开发环境
    ├── test.py      # 测试环境
    └── prod.py      # 生产环境

base.py(公共部分)

python 复制代码
"""
ShopX Django 配置 - 基础配置(所有环境共享)
"""
from pathlib import Path
from decouple import config

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

# ========== 核心安全配置 ==========
SECRET_KEY = config('DJANGO_SECRET_KEY')
DEBUG = config('DJANGO_DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config(
    'DJANGO_ALLOWED_HOSTS',
    default='*',
    cast=lambda v: [s.strip() for s in v.split(',')],
)

# ========== 应用注册 ==========
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # 第三方
    'rest_framework',
    'corsheaders',
    # 本项目
    'health',
]

# ========== 中间件 ==========
MIDDLEWARE = [
    # CORS必须在CommonMiddleware之前
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'shopx.urls'

# ========== 模板 ==========
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'shopx.wsgi.application'
ASGI_APPLICATION = 'shopx.asgi.application'

# ========== 数据库 ==========
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': config('DB_NAME', default='shopx'),
        'USER': config('DB_USER', default='root'),
        'PASSWORD': config('DB_PASSWORD'),
        'HOST': config('DB_HOST', default='127.0.0.1'),
        'PORT': config('DB_PORT', default='3306'),
        'OPTIONS': {
            'charset': 'utf8mb4',
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
        },
    }
}

# ========== 密码验证 ==========
AUTH_PASSWORD_VALIDATORS = [
    {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
    {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
    {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
    {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
]

# ========== 国际化 ==========
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_TZ = True

# ========== 静态文件 ==========
STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'

# ========== 媒体文件(用户上传) ==========
MEDIA_URL = 'media/'
MEDIA_ROOT = BASE_DIR / 'media'

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# ========== DRF ==========
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny'],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
    'DEFAULT_RENDERER_CLASSES': ['rest_framework.renderers.JSONRenderer'],
    'DEFAULT_PARSER_CLASSES': ['rest_framework.parsers.JSONParser'],
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 20,
}

# ========== CORS(M0级别够用)==========
CORS_ALLOWED_ORIGINS = [
    'http://127.0.0.1:5173',
    'http://localhost:5173',
]

# ========== 存储 ==========
STORAGES = {
    "default": {
        "BACKEND": "django.core.files.storage.FileSystemStorage",
    },
    "staticfiles": {
        "BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
    },
}

这段代码使用了python-decouple库,需要进行配置。后面第五节会单独讲。

dev.py

python 复制代码
"""开发环境配置"""
from .base import *

DEBUG = True
ALLOWED_HOSTS = ['*']

# 控制台邮件后端,方便开发期看邮件内容
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

test.py

python 复制代码
"""测试环境配置"""
from .base import *

DEBUG = False
# 用内存数据库跑测试,不污染真实数据
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': ':memory:',
    }
}

prod.py

python 复制代码
"""生产环境配置(占位)"""
from .base import *

DEBUG = False
# ALLOWED_HOSTS必须在.env里配

切换环境

通过 DJANGO_SETTINGS_MODULE 环境变量:

bash 复制代码
# 开发
export DJANGO_SETTINGS_MODULE=shopx.settings.dev
python manage.py runserver

# 测试
export DJANGO_SETTINGS_MODULE=shopx.settings.test
python manage.py test

# 生产
export DJANGO_SETTINGS_MODULE=shopx.settings.prod
gunicorn shopx.wsgi:application

为什么不直接用django-environ?

它功能更强,但配置文件要写一堆env()调用,对零基础读者不友好。

python-decouple配合.env文件足够本专栏用,后面生产部署时再考虑迁移。


五、配置python-decouple

python-decouple是从.env文件读配置的小工具。比os.environ多了几个能力:

  • 自动处理bool int list类型转换
  • 默认值
  • .env不存在时报错而不是悄悄用空值

项目根目录建 .env

⚠️ 必须放在shopx/.gitignore已忽略的路径下 。本专栏把.env放在backend/.env(不进 git)。

ini 复制代码
# Django
DJANGO_SECRET_KEY=dev-secret-key-change-me-in-prod
DJANGO_DEBUG=True
DJANGO_ALLOWED_HOSTS=*

# MySQL(密码要改)
DB_NAME=shopx
DB_USER=root
DB_PASSWORD=your_strong_password_here
DB_HOST=127.0.0.1
DB_PORT=3306

# Redis
REDIS_URL=redis://127.0.0.1:6379/0

创建数据库

bash 复制代码
mysql -uroot -p
sql 复制代码
CREATE DATABASE shopx DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
SHOW DATABASES;
EXIT;

💡 utf8mb4_unicode_ci是更精确的排序规则(比utf8mb4_general_ci准确但稍慢),适合需要中文排序的电商场景。

跑迁移

bash 复制代码
python manage.py migrate

输出类似:

text 复制代码
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  ...

迁移会自动建好django_*开头的内置表(admin、auth、sessions 等)。

验证表

bash 复制代码
mysql -uroot -p shopx -e "SHOW TABLES;"

应该看到 auth_user、django_session、django_migrations 等表。


六、DRF配置详解

DRF(Django REST Framework)是Django生态里最主流的REST API框架。本节把它的几个关键配置讲透。

全局配置项

已经在base.py中配置,这里再强调几个关键项:

python 复制代码
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny'],
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
    'DEFAULT_RENDERER_CLASSES': ['rest_framework.renderers.JSONRenderer'],
    'DEFAULT_PARSER_CLASSES': ['rest_framework.parsers.JSONParser'],
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 20,
}

各项含义

  • DEFAULT_PERMISSION_CLASSES:默认权限。M0阶段先用AllowAny(任何人都能访问),后面会收紧为IsAuthenticated
  • DEFAULT_AUTHENTICATION_CLASSES:默认认证方式。Session用于Django Admin登录,JWT用于API调用
  • DEFAULT_RENDERER_CLASSES:只输出JSON(不要HTML调试页面)
  • DEFAULT_PARSER_CLASSES:只接受JSON入参(不要form-urlencoded)
  • DEFAULT_PAGINATION_CLASS:默认分页器,列表接口自动分页,每页20条
  • PAGE_SIZE:默认每页条数

DRF 三件套

DRF把Web API抽象成三个层次:

  1. Serializer(序列化器)------ 数据格式转换 + 校验
  2. View(视图)------ 业务逻辑,接收请求、返回响应
  3. Router(路由器)------ URL路由(自动生成5个端点)

本讲只用到APIView,是最底层的写法。后面会升级到ViewSet + Router,代码量减少70%。


七、CORS预配置(M0级别)

我们在Vite里配了devServer.proxy------开发期能解决跨域。但生产环境(前端部署到shopx.com、后端在api.shopx.com)必须靠真正的CORS头。

安装与配置

django-cors-headers在INSTALLED_APPS和MIDDLEWARE都注册过了(见base.py)。CORS_ALLOWED_ORIGINS列出了允许跨域的前端源。

工作原理

浏览器看到http://shopx.com调http://api.shopx.com/api/v1/health/时:

  1. 浏览器发OPTIONS预检请求
  2. 后端检查Origin头是否在白名单
  3. 在白名单里 → 返回Access-Control-Allow-Origin: http://shopx.com
  4. 浏览器放行真实请求

M0级别配的就够开发用了

完整CORS原理(含Cookie携带、复杂请求、Origin校验原理)。


八、跑起来验证

启动服务

bash 复制代码
# 确认虚拟环境已激活、依赖已装
export DJANGO_SETTINGS_MODULE=shopx.settings.dev
python manage.py runserver 0.0.0.0:8000

终端输出:

text 复制代码
Watching for file changes with StatReloader
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.

测试三个端点

1. 健康检查接口:

浏览器打开 http://127.0.0.1:8000/api/v1/health/,应该看到:

json 复制代码
{
  "status": "ok",
  "service": "shopx",
  "version": "0.1.0"
}

2. Django Admin登录页:

浏览器打开http://127.0.0.1:8000/admin/,看到登录页。账号还没建,先用命令行建一个superuser:

bash 复制代码
python manage.py createsuperuser
# 输入用户名、邮箱、密码

然后用这个账号登录Admin,能看到health app已经在管理界面里(虽然暂时空)。

3. 前后端联调:

第4讲的前端只渲染了静态页面,还没调过后端。

这一节我们把App.vue改一版,让它启动时请求/api/v1/health/,把后端返回的版本号显示在页面上。

这是整个专栏第一次前后端真实通信,也是M0里程碑最关键的验证。

3.1. 修改 frontend/src/App.vue
vue 复制代码
<script setup lang="ts">
import { ref, onMounted } from 'vue'

interface HealthResponse {
  status: string
  service: string
  version: string
}

const year = new Date().getFullYear()
const health = ref<HealthResponse | null>(null)
const error = ref<string | null>(null)

onMounted(async () => {
  try {
    // 走 Vite proxy,实际请求 http://127.0.0.1:8000/api/v1/health/
    const res = await fetch('/api/v1/health/')
    if (!res.ok) throw new Error(`HTTP ${res.status}`)
    health.value = await res.json()
  } catch (e) {
    error.value = e instanceof Error ? e.message : String(e)
  }
})
</script>

<template>
  <div class="hello">
    <div class="brand">ShopX</div>
    <h1>Hello ShopX</h1>
    <p class="subtitle">从零到上线 · 全栈电商项目</p>

    <div v-if="health" class="health ok">
      ✅ 后端连接成功 · {{ health.service }} v{{ health.version }}
    </div>
    <div v-else-if="error" class="health err">
      ❌ 后端连接失败:{{ error }}
    </div>
    <div v-else class="health loading">
      ⏳ 正在连接后端...
    </div>

    <p class="muted">© {{ year }} · 第 5 讲里程碑</p>
  </div>
</template>

<style scoped>
.hello {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #0f1b2d 0%, #1a2a44 100%);
  color: #ffffff;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', sans-serif;
}
.brand {
  font-size: 18px;
  letter-spacing: 6px;
  color: #ffb020;
  margin-bottom: 24px;
}
h1 {
  font-size: 64px;
  margin: 0 0 16px;
  font-weight: 500;
}
.subtitle {
  font-size: 18px;
  color: #cbd5e1;
  margin: 32px 0;
}
.health {
  padding: 10px 20px;
  border-radius: 8px;
  font-size: 15px;
  margin-bottom: 40px;
}
.health.ok {
  background: rgba(34, 197, 94, 0.15);
  color: #4ade80;
}
.health.err {
  background: rgba(239, 68, 68, 0.15);
  color: #f87171;
}
.health.loading {
  background: rgba(148, 163, 184, 0.15);
  color: #94a3b8;
}
.muted {
  color: #8a93a6;
  font-size: 14px;
}
</style>
3.2. 确认两个服务都在跑
bash 复制代码
# 终端 1:后端
cd ~/workspace/shopx/backend
source ../.venv/bin/activate
export DJANGO_SETTINGS_MODULE=shopx.settings.dev
python manage.py runserver 0.0.0.0:8000

# 终端 2:前端
cd ~/workspace/shopx/frontend
pnpm dev
3.3. 验证联调

浏览器打开http://127.0.0.1:5173/,你应该看到:

text 复制代码
ShopX
Hello ShopX
从零到上线 · 全栈电商项目
✅ 后端连接成功 · shopx v0.1.0
© 2026 · 第 5 讲里程碑

打开开发者工具 → Network面板,能看到一条health/请求:

  • Request URL: http://127.0.0.1:5173/api/v1/health/
  • Status: 200
  • Response: {"status":"ok","service":"shopx","version":"0.1.0"}

请求地址是5173不是8000 ------这正是Vite proxy在起作用。Vite收到/api/v1/health/后,转发给http://127.0.0.1:8000,浏览器完全无感,也就没有跨域问题。

3.4. 如果看到「❌ 后端连接失败」

按顺序排查:

现象 原因 解决
HTTP 404 后端URL没挂上 检查shopx/urls.py有path('api/v1/', include('health.urls'))
Failed to fetch 后端没跑,或proxy没配 确认8000端口能访问;检查vite.config.ts的server.proxy
CORS报错 请求没走proxy,直接打到8000 确认fetch写的是/api/v1/health/,不是http://127.0.0.1:8000/api/v1/health/

💡 关键 :前端代码里永远写相对路径 /api/v1/...,不要写完整后端地址。开发期靠Vite proxy,生产期靠Nginx反代,前端代码不用改。

3.5. 提交这一节的改动
bash 复制代码
cd ~/workspace/shopx
git add frontend/src/App.vue
git commit -m "feat(frontend): 第 005 讲 App.vue 接入 health 接口完成联调"

---

## 九、生成requirements.txt锁版本

`pip freeze` 导出所有依赖到 `requirements.txt`:

```bash
pip freeze > requirements.txt

requirements.txt 长这样:

text 复制代码
Django==6.1
djangorestframework==3.18.x
djangorestframework-simplejwt==5.5.x
django-cors-headers==4.9.x
python-decouple==3.8
mysqlclient==2.2.x
redis==6.2.x
celery==5.6.x

💡 小版本号(x)随安全补丁更新,不影响教程内容。之前已说明:本专栏锁定大版本,小版本跟随最新补丁。

一键起项目脚本

新建backend/run_dev.sh:

bash 复制代码
#!/usr/bin/env bash
set -e
cd "$(dirname "$0")"
export DJANGO_SETTINGS_MODULE=shopx.settings.dev
python manage.py runserver 0.0.0.0:8000
bash 复制代码
chmod +x run_dev.sh

下次启动直接bash run_dev.sh。


十、提交与打tag

按第3讲的提交规范,本讲至少两个commit:

bash 复制代码
cd ~/workspace/shopx

# 第一个commit:Django工程初始化 + settings分层
git add backend/manage.py backend/shopx backend/requirements.txt
git commit -m "feat(backend): 第 005 讲 初始化 Django 工程与 settings 分层"

# 第二个commit:health app + DRF + CORS配置
git add backend/health backend/.env.example backend/run_dev.sh
git commit -m "feat(backend): 第 005 讲 health 接口与 DRF/CORS 接入"

# 推送特性分支
git push -u origin feature/lecture-005-backend-scaffold

合并到develop:

bash 复制代码
git switch develop
git merge --squash feature/lecture-005-backend-scaffold
git commit -m "feat(backend): 第 005 讲 Django 5 后端骨架与 DRF 接入"
git tag lecture/005
git push origin develop
git push origin lecture/005

删掉feature分支

bash 复制代码
git branch -d feature/lecture-004-frontend-scaffold
#删除远程分支
git push origin --delete feature/lecture-004-frontend-scaffold

十一、本讲作业

  1. 跑通/api/v1/health/
  2. 创建superuser并登录/admin/
  3. 故意把.env 里的 DB_PASSWORD改错,看报错信息,再改回来------体验一下「密码错」的报错长什么样
  4. 试bash run_dev.sh一键启动
  5. 完整跑一次「前5讲里程碑」自检 :
    • 浏览器打开 http://127.0.0.1:5173/ 看到Hello ShopX
    • 浏览器打开 http://127.0.0.1:8000/api/v1/health/ 看到ok
    • 浏览器开发者工具Network看到前端成功调通后端
  6. 截图三个画面,合成一张「M0里程碑成就」图发评论区

十二、常见报错速查表

报错 原因 解决
django-admin: command not found 没装Django或没激活虚拟环境 pip install "Django>=6.1,<6.2",确认终端前缀有(shopx)
mysqlclient装失败:mysql_config not found macOS缺mysql-client brew install mysql-client pkg-config,加export PKG_CONFIG_PATH="/opt/homebrew/opt/mysql-client/lib/pkgconfig"
django.db.utils.OperationalError: (1045, "Access denied") MySQL用户名/密码错 改.env里的DB_USER / DB_PASSWORD
Unknown database 'shopx' 数据库没建 mysql -uroot -p -e "CREATE DATABASE shopx DEFAULT CHARACTER SET utf8mb4;"
CORS报错No 'Access-Control-Allow-Origin' header 前端访问后端但CORS_ALLOWED_ORIGINS没配 检查settings/base.py里的origins列表
ModuleNotFoundError: No module named 'decouple' python-decouple没装 pip install python-decouple
ALLOWED_HOSTS报错Invalid HTTP_HOST ALLOWED_HOSTS没收当前访问的域名 dev环境允许 ['*'],prod必须明确写域名
ModuleNotFoundError: No module named 'health' health app没注册 INSTALLED_APPS里加'health'
启动后看到的是Django欢迎页而不是JSON URL没挂上 检查shopx/urls.py是否有path('api/v1/', include('health.urls'))

十三、术语自查报告

  • ✅ Django 6.1 / DRF 3.18.x 精确版本
  • ✅ startproject shopx .末尾的点含义写清
  • ✅ INSTALLED_APPS / MIDDLEWARE大小写正确
  • ✅ MIDDLEWARE 顺序:CORS必须在CommonMiddleware之前
  • ✅ utf8mb4(不是utf8)写全
  • ✅ APIView / Response来自rest_framework
  • ✅ python-decouple名字写对(不是python_decouple)
  • ✅ DJANGO_SETTINGS_MODULE环境变量名写对
  • ✅ ALLOWED_HOSTS不能用*在生产
  • ✅ mysqlclient装失败原因(mysql_config not found)写对
  • ✅ CORS是「跨源资源共享」(Cross-Origin Resource Sharing)
  • ✅ pip freeze > requirements.txt锁版本
  • ✅ WSGI同步 / ASGI异步区别一句话写明
  • ✅ API版本号/api/v1/写明意义

自查通过。无禁用词。

最后:M0 里程碑,你已解锁

如果你跟着跑通了health接口,评论区打卡一句:

第005讲签到,M0里程碑已解锁

  • 点赞:让更多正在搭后端的人看到
  • 收藏:配settings分层、DRF配置时随时回查
  • 关注:追更不迷路

我们第6讲见。

相关推荐
TomEval1 小时前
【测AI】第05篇:Python 爬虫进阶 —— 动态页面爬取与 Scrapy 框架
人工智能·爬虫·python·scrapy·自动化
IT枫斗者枫哥1 小时前
UPDATE影响0行,接口却返回成功:把版本冲突接回业务
java·后端
huisheng_qaq1 小时前
【Python基础篇-07】深入理解python的面向对象编程
python·多态·继承·面向对象编程·封装
FanetheDivine1 小时前
学习python 2.语法速览
python
奕鼎竜瑆1 小时前
[新手小白也能学会] 01-PyTorch框架使用(上)
人工智能·pytorch·python
miss1 小时前
从零做一个可视化规则引擎:Vue3 递归条件树 + 双引擎结果对比
前端·vue.js·typescript
海天一色y1 小时前
图像分割全解析:从经典算法到深度学习的原理与实战(Python + MATLAB)
python·深度学习·算法
一帅1 小时前
Muzzle:给 Java Agent 戴上的"安全口罩"
后端
Bazingga2 小时前
从0到1吃透Function Calling:Spring AI完整实战
后端