简介:一份基于Django框架的完整电商网站项目源码,面向计算机、电子信息等相关专业的大学生,可作为课程设计、期末大作业或毕业设计的直接参考。项目以Django的MTV架构为核心,覆盖模型定义、ORM迁移、视图逻辑、模板渲染、URL路由等后端要点,并集成商品搜索、分类浏览、购物车及第三方支付接口等电商典型功能,同时包含SQL注入、XSS等安全防护实践。资源压缩包共1794个文件,大小约5.86MB,其中以JavaScript(1075个)、CSS样式表(139个)、Python源码(137个)及HTML模板(38个)为主,辅以图片、字体等静态资源,目录结构完整,便于按模块查阅。该资料已有33人学习下载,适合需要快速理解Django电商开发全流程、参考前端布局与后端实现细节的读者。
1. 基于 Django 的电商网站压缩包:不是你想象的那种“毕业设计垃圾堆”
做毕设或者课程设计的人最怕的,不是不会写代码,而是打开一个号称“Django 电商网站”的项目包,发现里面既没有商品模块,也没有购物车,跑起来连登录都报错。这份基于 Django 的电商网站 zip 不一样的地方在于:它是冲着一句话交付去的——解压、配环境、迁移数据库、开后台,然后就能在浏览器里看到完整电商流程。这个包里包含商品、购物车、订单、用户,以及后台管理用的 Django Admin,功能上是典型 B2C 商城的最小闭环。
它适合两种人:一是时间紧、任务重,需要在两周内拿出可演示系统的计算机专业学生;二是刚听完 Django 基础课,想找一个完整项目来复盘视图、模型、模板三层是怎么配合的入门者。如果你是零基础,这个包也能用,但建议先补一下 Django 的 MTV 概念再来动它。接下来我会按真实拆包顺序,从目录结构、环境配置、二次开发,一路讲到最后交付时最容易踩的坑。
2. 拆包之前先看结构:电商项目的模块划分与运行前提
2.1 电商项目的标准模块切分:先搞清哪个 app 负责哪件事
拿到压缩包后先别急着解压,先看包内目录层级。一个合格 Django 电商项目,至少要有四个独立 app:商品、用户、购物车、订单。有的项目会把用户操作记录单独拆出来,做成一个名为 operation 的 app,用于记录浏览历史和收藏。模块划分遵循一个核心原则:一个 app 只干一类事,这样后续改需求的时候,改动范围是可控的。
常见的模块划分和数据关系是这样的:
| 模块 | 核心模型 | 负责的事 | 关键字段 |
|---|---|---|---|
| goods | Goods / GoodsCategory | 商品列表、商品详情、分类筛选 | name、category、price、stock、image |
| user | UserProfile / UserAddress | 注册登录、收货地址管理 | username、mobile、address |
| cart | Cart / CartItem | 购物车增删改、数量调整 | goods、user、num、selected |
| order | Order / OrderGoods | 下单、订单状态流转、订单商品快照 | status、total_money、order_sn、goods |
模块之间靠外键关联:购物车条目通过外键指向商品和用户,订单商品通过外键指向订单,同时存一份商品名称和价格快照。为什么订单里要存快照?因为下单那一刻商品的名称、价格、图片需要固定下来,之后商品改价了,历史订单不能跟着变。这个设计理念在答辩时被老师问到概率很高,你可以顺着这个逻辑讲下去。
模板的存放位置也有讲究。商品列表页、商品详情页、购物车页、订单确认页、个人中心页面,会有对应的模板文件放在各自的 templates 目录下,而不是全部堆在项目根目录。如果你打开项目发现共用一套基础模板 base.html,说明项目已经做了模板继承,这是加分项,起码说明不是随手拼出来的代码。
2.2 运行环境三个前提:Python 版本、虚拟环境、依赖清单
这个项目基于 Django 框架,依赖的核心包不多,但版本不匹配会让它直接罢工。建议先用以下命令确认 Python 版本,Django 项目在 Python 3.6 以上才能流畅运行,这里最好使用 3.8 到 3.11 之间的稳定版本。
python --version # 建议输出 Python 3.8.x 或更高版本拿到项目包之后,永远不要直接使用全局环境去装依赖,因为你电脑上可能装了好几个项目,依赖版本互相冲突,到时候想排查都无从下手。正确做法是在项目根目录创建独立虚拟环境:
cd django-mall # 进入项目根目录,manage.py 所在位置 python -m venv venv # 创建虚拟环境,文件夹名为 venv # Windows 激活方式 venv\Scripts\activate # macOS / Linux 激活方式 source venv/bin/activate激活成功后,命令行提示符前会出现(venv)字样。这时再安装依赖,依赖只会装进这个项目的虚拟环境里,不会污染全局环境,Python 环境出问题也能随时删掉重建,这个习惯值得长期保持。
接下来安装依赖清单:
pip install -r requirements.txt如果项目没有 requirements.txt,常见做法是自己根据项目代码逐个安装核心依赖。一个典型 Django 电商项目最少需要依赖这些:Django、Pillow、mysqlclient 或 PyMySQL、django-crispy-forms。Pillow 负责处理商品图片上传,mysqlclient 负责连接 MySQL;如果你打算先用自带的 SQLite 跑通,可以暂时不装数据库驱动。国内网络环境安装慢,可在 pip 命令后面加清华镜像源,速度会明显快很多。加上源之后的命令是这样的:
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple这里的-i参数指定了包下载源,镜像站点拥有主流 Python 包的完整副本,省去你反复重试的时间。
2.3 解压姿势直接影响项目能否跑起来:新手在这里翻车
很多人在这一步就出问题,项目包是 zip 格式,系统自带的解压功能有两点隐患。第一,微软内置解压对文件名的编码默认识别较差,项目里如果用中文命名了上传文件或静态资源目录,解压后可能出现乱码目录名,导致 Django 模板加载路径错误。第二,解压出的文件可能被系统打上“来自其他计算机”的标记,后面运行时会弹出安全确认。
推荐使用 7-Zip 或 Bandizip 这类第三方工具解压,右键解压到当前文件夹即可。如果系统右键菜单里没有相关选项,也可以用 PowerShell 自带的 tar 命令解压:
tar -xf django-mall.zip这一步执行完毕,项目根目录应该出现 manage.py 文件和项目同名子目录,这才是正确结构。如果你解压出来只有一层嵌套目录,项目文件跑到了内层,运行前建议把内层内容整体移到外层,否则后面输入python manage.py runserver会提示找不到 manage.py。整理好目录结构再继续。
3. 把压缩包变成能访问的网站:迁移、初始数据、启动三步走
3.1 首要问题:告诉 Django 用哪个数据库
启动项目前必须确认数据库配置。打开项目同名目录下的 settings.py,找到 DATABASES 配置节。如果默认配置是 SQLite,那么你什么都不用改,直接往下走。如果配置的是 MySQL,就需要先在本机准备好 MySQL 服务,再在数据库里创建一个空库,不然 manage.py 执行迁移时会直接报连接错误。
MySQL 8.0 在 Windows 上的安装方式,可以直接用官方免安装 zip 包:把 zip 解压到指定目录,配置好 my.ini 文件,再以管理员权限执行mysqld --initialize-insecure初始化,最后执行mysqld --install注册成 Windows 服务。这些操作都依赖压缩包里的解压和初始化步骤,正好和这个项目包的使用思路一致。
使用 MySQL 的 Django 项目,settings.py 的典型配置长这样:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'django_mall', 'USER': 'root', 'PASSWORD': '你自己的密码', 'HOST': '127.0.0.1', 'PORT': '3306', } }务必注意,这里 NAME 字段填的是数据库名称,不是表名,且这个库需要提前创建好。创建数据库的命令是CREATE DATABASE django_mall CHARACTER SET utf8mb4;,在终端或者 MySQL 客户端里执行都行。字符集一定选 utf8mb4,不要用 utf8,不然保存 emoji 表情符号时会报字符集错误。
配置完成后,执行迁移命令:
python manage.py makemigrations python manage.py migratemakemigrations 是把模型定义编译成迁移文件,migrate 是把迁移文件里的操作真正落实到数据库。前端更新数据库表结构时,这两条命令配合使用。执行完 migrate 后数据库会出现多张以 app 名称为前缀的数据表,比如 goods_goods、order_order、user_userprofile 这些。
这里说一个原则:settings.py 里没有配置好数据库之前,绝对不要盲目执行 migrate。常见情况是打开项目就顺手敲 migrate,结果终端抛出一大堆连接错误,然后开始怀疑项目包有问题。先确认配置,再执行迁移,顺序不能反。
3.2 创建管理员账号和初始商品数据
数据库迁移成功之后,系统还是空的,既没有管理员,也没有商品数据。创建管理员账号用 Django 自带命令:
python manage.py createsuperuser执行后按提示输入用户名、邮箱、密码。密码要求至少八位,且不能是纯数字,否则会提示重新输入。创建完之后不需要额外注册,这个账号默认拥有全部后台权限。
接下来处理商品数据。有些项目会在压缩包里带一个 fixtures 目录,里面放初始数据文件。导入初始数据用:
python manage.py loaddata initial_data.jsonfixtures 数据文件是 Django 通过 dumpdata 命令导出的,loaddata 导入时会自动处理外键关联关系,所以导入顺序不用你操心。导入完成后,在浏览器里访问后台地址127.0.0.1:8000/admin,就能看到刚才创建的管理员登录界面,登录进去商品列表里已有数据。
如果项目包里没有附带数据文件,你也不必手动一条一条在页面里添加。写一个临时脚本,在 Django shell 里批量造数据即可:
# 创建临时数据脚本,用 manage.py shell 执行 python manage.py shell << 'EOF' from goods.models import GoodsCategory, Goods from django.contrib.auth import get_user_model User = get_user_model() admin_user = User.objects.filter(is_superuser=True).first() print('当前管理员:', admin_user) category, _ = GoodsCategory.objects.get_or_create( name='数码产品', defaults={'desc': '演示分类'} ) for i in range(1, 6): Goods.objects.get_or_create( name=f'演示商品-{i}', defaults={ 'category': category, 'price': 99.00 + i, 'stock': 100, } ) print('商品创建完成') EOF代码逻辑是复习 ORM 查询和创建对象的好机会:get_or_create 先执行查询,查不到再执行创建;defaults 字典里放除查询条件以外的字段值。循环里生成五个商品名称和价格,保证首页商品列表不是空白。这个脚本执行完可以在后台查看,也可以直接访问前台商品列表确认。
3.3 启动服务并验证三个入口:前台首页、商品详情、后台管理
数据就绪后,启动开发服务器:
python manage.py runserver默认监听 8000 端口,浏览器访问127.0.0.1:8000。看到首页商品列表后,逐个验证以下入口:
| 验证入口 | 访问地址 | 预期效果 |
|---|---|---|
| 商品列表 | 127.0.0.1:8000 | 显示五个商品卡片和价格 |
| 商品详情 | 127.0.0.1:8000/goods/1/ | 显示该商品完整信息,图片能正常加载 |
| Django 后台 | 127.0.0.1:8000/admin | 管理员登录成功,能操作商品和订单 |
这里先记住一个验证标准:如果商品详情页里的图片裂开了,先去看控制台静态文件 404 报错,这是后续避坑章节要处理的高频问题。三个入口都正常后,项目才算真正跑通,后面的二次开发也才有基础。开发服务器显示页面底部有 Debug 工具栏,属于正常现象,交付前再关闭就好。
4. 能跑起来只是开始:商品、购物车、订单这三个模块怎么改
4.1 商品详情页的 URL 设计:反查 URL 是模板里的隐藏考点
商品列表页打开后,商品标题是可点击链接,点击后进入详情页。这里面 URL 路由设计很关键。现代 Django 推荐使用 path 函数而不是老式正则路由,商品详情的路由定义通常长这样:
# urls.py 文件 from django.urls import path from goods import views urlpatterns = [ path('goods/<int:goods_id>/', views.goods_detail, name='goods_detail'), ]<int:goods_id>表示 URL 中这一段是整数,Django 会自动校验类型并传给视图函数。view 函数接收参数后查询商品对象:
# goods/views.py 文件 from django.shortcuts import render, get_object_or_404 from .models import Goods def goods_detail(request, goods_id): goods = get_object_or_404(Goods, id=goods_id) return render(request, 'goods/detail.html', {'goods': goods})模板里指向详情页的写法,优先使用 name 反查,而不是硬编码 URL:
<a href="{% url 'goods_detail' goods.id %}">{{ goods.name }}</a>这样做的价值在于:如果哪天 URL 规则变了,比如加了一个语种前缀,后台代码不需要跟着改,模板会根据 name 自动生成新地址。新手最容易犯的错是在模板中直接写死/goods/1/,一旦商品 ID 变成两位数还能跑,但改成其他路由规则就会全部失效。答辩时老师大概率也会问“URL 怎么管理”,你直接回答用的是反向解析,比解释半天路由正则要加分。
如果你要新增一个商品分类功能,需要新建 app 而不是在现有项目里硬塞代码。执行命令python manage.py startapp category,创建完成后把 category 加入 settings.py 的 INSTALLED_APPS 列表,再去 category/models.py 里写模型。创建 app 本身不复杂,但漏掉 INSTALLED_APPS 注册是最常见的新手错误,后续加菜单、加页面全部不会生效。
4.2 购物车实现方式:先看懂它是存 Session 还是存数据库
课程设计级别的购物车,实现方式有两种。一种是完全基于 Session:把商品 ID 和数量存在用户浏览器会话里,未登录也能加购,下单时再写入订单表。另一种是数据库购物车表:购物车条目落库,需要通过用户外键关联查询。两种方案各有取舍,Session 方案不需要建表,数据临时存储,换台电脑购物车就没了;数据库方案能保存用户购物车状态,但需要处理用户未登录时的临时购物车合并逻辑。
拿到这个项目包,你可以用一条命令查看它的购物车实现方式:
python manage.py shell from cart import models as cart_models import inspect print(cart_models.__file__)打开该 app 的 models.py 文件,看里面是否定义了 Cart 或者 CartItem 数据模型。如果定义了,说明走的是数据库方案;如果整个 cart app 只有 views 和 urls,没有 models 定义,那它大概率是 Session 方案。
我在实际使用中更建议数据库方案,理由很简单:毕业设计演示时需要向老师展示数据持久化,Session 方案刷新页面后一旦过期,购物车内容就没了,现场演示翻车风险高。数据库方案还能在 Django 后台直接看到购物车数据,方便你给老师展示“看,这里能看到某用户的购物车记录”。
购物车表的设计核心字段通常是这样:
# cart/models.py 示例 class CartItem(models.Model): user = models.ForeignKey('user.UserProfile', on_delete=models.CASCADE, verbose_name='用户') goods = models.ForeignKey('goods.Goods', on_delete=models.CASCADE, verbose_name='商品') goods_num = models.IntegerField(default=1, verbose_name='购买数量') is_selected = models.BooleanField(default=True, verbose_name='是否勾选')这里注意 user 字段用的是字符串引用而不是直接 import 模型类,好处是避免循环导入问题。goods 和 user 都是外键,当主表记录被删除时,on_delete=models.CASCADE级联删除购物车里的对应条目,这是订单场景下的合理预设。
当购物车里的商品要删除对象时,ORM 的操作是刷掉一行代码的事:
CartItem.objects.filter(user=request.user, goods_id=goods_id).delete()filter 先定位符合条件的记录,然后执行删除,最后返回被删条数。Django 执行查询-删除对象有一套固定的链式方法,在 shell 里反复多试几次就能熟悉套路。核心原则是明确过滤条件,条件写得太窄删不掉,写得太宽会误删数据。上面的示例用了两个过滤条件:当前用户和商品 ID,范围是精准的。
4.3 订单状态流转:用状态整数字段和 Django Admin 把流程撑起来
订单模块是整个项目里最容易在答辩时出彩的部分。订单状态一般用整数表示,因为 Django 默认的 choices 字段加上状态中文映射后,后台会显示下拉框,操作起来非常直观。常见状态设计如下:
| 状态整数值 | 状态含义 | 后台显示 |
|---|---|---|
| 0 | 待支付 | 橙色标签 |
| 1 | 已支付待发货 | 蓝色标签 |
| 2 | 已发货 | 绿色标签 |
| 3 | 已完成 | 灰色标签 |
| 4 | 已取消 | 红色标签 |
模型里这样定义:
# order/models.py 示例 class Order(models.Model): STATUS_CHOICES = ( (0, '待支付'), (1, '待发货'), (2, '待收货'), (3, '已完成'), (4, '已取消'), ) order_sn = models.CharField(max_length=30, verbose_name='订单编号') user = models.ForeignKey('user.UserProfile', on_delete=models.CASCADE, verbose_name='下单用户') total_money = models.DecimalField(max_digits=9, decimal_places=2, verbose_name='订单总价') status = models.SmallIntegerField(choices=STATUS_CHOICES, default=0, verbose_name='订单状态') create_time = models.DateTimeField(auto_now_add=True, verbose_name='下单时间')header 状态流转的逻辑是:用户提交订单生成待支付记录,支付成功后台把状态改成 1,商家发货改成 2,用户确认收货改成 3。但真实商城支付需要接入支付宝或微信支付,这在毕设里不现实,完整的演示一般用 Django Admin 手动改状态来代替支付回调。
把订单模型注册进 Django Admin 后,在后台可以直接筛选不同状态的订单,这对老师演示非常直观。注册代码很简单:
# order/admin.py 示例 from django.contrib import admin from .models import Order @admin.register(Order) class OrderAdmin(admin.ModelAdmin): list_display = ('order_sn', 'user', 'total_money', 'status', 'create_time') list_filter = ('status',) search_fields = ('order_sn',)list_display控制后台列表展示哪些列,list_filter在右侧生成状态筛选器,search_fields让订单号可搜索。这三行配置就能把订单列表变得像一个真实的运营后台。答辩演示时,演示完前台下单,再切到后台把订单状态从“待支付”改成“待发货”,既展示了前后端配合,又能解释状态字段的意义,这套动作几乎不会有冷场。
5. 避坑专场:跑 Django 电商项目最容易翻车的五个真实原因
5.1 商品图片全部裂开,控制台输出大量静态文件 404
现象是:后台能登录,商品名称和价格都正常,但每张商品图都显示破碎图标,浏览器控制台 Network 里全是.css、.jpg、.js请求返回 404。
原因有三个,按概率从高到低排。第一,模板文件头部缺少静态文件加载声明,你根本没有用{% load static %}。第二,settings.py 里 STATIC_URL 配置错误或者没配置。第三,项目使用 DEBUG=False 运行,Django 默认不会处理静态文件路径。
解决方式分两步。先确认 settings.py 里的静态文件配置,这是最常用的一段配置:
# settings.py STATIC_URL = '/static/' STATICFILES_DIRS = [ BASE_DIR / 'static', ]再检查模板底部或顶部有没有加载静态文件指令:
{% load static %} <img src="{% static 'images/goods/1.jpg' %}" alt="商品图片">static 写法会把图片路径映射成/static/images/goods/1.jpg,与 STATIC_URL 匹配,浏览器才能按这个路径找到文件。顺便检查一下项目里是否有 static 目录且图片真实存在,很多压缩包解压后目录完整,但图片体积被阉割或路径被改成绝对路径,也会失效。
5.2 执行 migrate 时提示 table already exists 或 duplicate column name
现象是:重新配置数据库后跑 migrate,结果刷出一堆报错,提示某张表已存在,或者某一列重复添加。
原因是:数据库不是全新的,可能是你之前执行过一次 migrate,表结构已经创建;也可能是项目包作者导入了 sql 文件,表结构与 Django 迁移记录不匹配。第二种情况最常见,数据库有表但 django_migrations 表没有对应记录,Django 认为这些表不存在,尝试重建时就和已有表冲突。
解决方法是:先确认当前数据库是否有业务数据需要保留。如果不需要保留,直接删库重建最干净:在 MySQL 中执行DROP DATABASE django_mall;,再重新CREATE DATABASE django_mall CHARACTER SET utf8mb4;,然后重新 migrate。需要保留数据时,可以查看迁移记录和实际表结构的关系,但作为课程设计,删库重来反而更快,不影响最终交付。注意,血泪经验是:迁移报错的时候看报错前几行,它会告诉你具体冲突的表名,比你想省事去百度整段报错要准确得多。
5.3 安装 mysqlclient 永远失败,报错 Microsoft Visual C++ 14.0 is required
现象是:在 Windows 上执行pip install mysqlclient长时间无响应或直接编译报错,提示缺少 Visual C++ 编译器。
原因是:mysqlclient 有 C 扩展,Windows 上需要对应版本的编译工具链,机器上没有编译工具时安装必然失败。这不是项目代码的问题,是依赖包本身跨平台编译的兼容性问题,PyMySQL 是更亲和的替代。
解决方式:Django 在连接 MySQL 时通常使用 MySQLdb 这个名字,PyMySQL 提供兼容接口,可以把域名替换过来,让它伪装成 MySQLdb。在项目主目录的__init__.py文件中加入两行代码:
# 项目目录下的 __init__.py import pymysql pymysql.install_as_MySQLdb()然后把 mysqlclient 从 requirements.txt 里删掉,改为安装并依赖 pymysql,在 requirements.txt 中写上:
pip install pymysql之后重新执行 migrate,数据库可以正常连接。这个方法在很多实战项目里都用得上,属于不用买后悔药就能解决的问题。顺手把 pandas 之类的 C 扩展相关包先装好,避免后面再踩一次编译坑。
5.4 解压报错或目录名变成乱码
现象是:解压 zip 包过程中提示 CRC 校验失败,或者解压出来目录名像是编码错误,例如locale乱码。
原因是:压缩包在传输过程被截断或损坏,这是最糟糕的情况;另一种情况是解压软件没正确处理 ZIP 文件的 UTF-8 编码标识,Windows 自带解压对此支持不好。
解决方式分两种,先重新下载 zip 包,确认文件大小与发布方给的官方大小一致。如果确认文件完整,但解压出来依然乱码,用 7-Zip 打开压缩包,手动复制内层目录到目标路径。tar 命令在 PowerShell 里也可以解压,它能保留一部分编码标记。操作完成后,进入项目目录手动检查一下 manage.py 路径下是否存在非 ASCII 字符路径。我习惯把解压后的项目整体放在纯英文路径下,比如D:\workspace\django-mall,避免 Windows 对中文字符路径做特殊处理,这也是很多新手项目名带中文导致报错的根源。万一路径里有中文导致模板加载失败,就用这个方法处理,控制变量去排除。
5.5 提交订单时 403 Forbidden,或 POST 请求被拦截
现象是:商品列表正常、购物车正常,但点击“提交订单”按钮后页面弹出 403 错误,或者直接 500 报错。
原因是:Django 内置了 CSRF 保护机制,表单里缺少{% csrf_token %}令牌,或者在提交 POST 请求时视图函数抛了异常而 Request 对象不存在相应的判断。模板表单里没带令牌是新手最经典的翻车点。
解决方式是在所有<form>表单内部第一行加入模板标签:
<form method="post" action="{% url 'create_order' %}"> {% csrf_token %} <!-- 其他表单字段 --> </form>加入后在模板渲染时 Django 会自动生成一个隐藏的 csrfmiddlewaretoken 字段,服务端验证通过后请求才会进入视图函数。如果仍然 500,打开 runserver 终端的完整堆栈,最后一行会指出行号与异常类型。新手最容易忽略的细节是订单明细列表在 POST 后没有取到,购物车 session 被 clear 掉导致写入空订单数据。这类问题本质上是代码执行顺序,先查数据库里的订单记录数量,再对照终端日志,发生顺序就能定位。
6. 交付前最后一次验证:从空数据库开始,四十分钟走完完整回归
毕业设计答辩有个铁律:不要在开发环境上演示,要在验收环境上走一遍完整链路。最有效的验证方法是把当前数据库整个清掉,然后从最原始状态重新走一遍流程。这样能暴露所有和静态数据、默认配置相关的问题,这些在开发环境长期运行中早已被掩盖。
我用得最多的做法是写一个简单的一键验证脚本,跑一遍核心页面响应状态,不依赖浏览器也能快速确认服务正常:
# verify.py:用 Django 自带的测试客户端做冒烟测试 import os import django os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_mall.settings') django.setup() from django.test import Client c = Client() urls = ['/', '/goods/1/', '/cart/', '/user/login/'] for url in urls: resp = c.get(url) print(f'{url} -> {resp.status_code}')脚本用 Django test client 分别请求首页、商品详情、购物车页面,把 HTTP 状态码打印出来。200 代表可访问,404 代表该排查路由,500 代表视图有异常。这个脚本要求数据库里商品 ID 为 1 的记录存在,如果你的初始数据第一个商品 ID 不一定是 1,就把goods/1/换成实际 ID。跑出来全 200 再进浏览器手动操作一遍重点链路。
有一个点容易被忽略:Django 的 test client 默认不会执行真实数据库写入,它会用内存镜像数据库跑测试,因此这张验证不会污染你现有的演示数据。这个冒烟脚本的价值,是让你在临时环境里用最快速度确认服务是否可用。完整交付检查清单如下:
| 顺序 | 检查项 | 通过标准 |
|---|---|---|
| 1 | 全新数据库 + migrate | 数据库表创建无报错 |
| 2 | 导入初始数据或造数 | 后台能看到商品分类和商品 |
| 3 | runserver 启动 | 首页商品列表渲染正常 |
| 4 | 用户注册登录 | 注册成功并跳转至个人中心 |
| 5 | 商品加购物车 | 购物车数量 +1 |
| 6 | 下单并确认订单 | 订单状态为待支付 |
| 7 | 后台修改订单状态 | 状态流转正常 |
| 8 | 停服重启 | 数据不丢失 |
说一个我自己经历过的教训。有一年我拿一个 Django 商城项目做公开演示,开发环境跑了一个月一切正常,结果演示当天用的是另一台机器,数据库是全新的,我自信过头没有从头跑一遍。打开首页之后,商品分类和商品列表全是空白,因为没有导入初始数据。当场整个人都蒙了,只能一边解释“让我看下数据库”,一边手动补数据,体验非常狼狈。从那以后,我养成了强制习惯:每交付一个 Django 项目,不管时间多赶,至少从空数据库到首页数据完整展示这套流程必须完整跑一遍,跑不完宁愿晚点交付也不提前结束。写这篇文章时,我又把这份 zip 包从头按这个顺序解压跑了一次,希望帮到你。
本文还有配套的精品资源,点击获取