当前位置: 首页 > news >正文

Django REST后端 + Vue前端的可运行电商毕设项目(含数据导入、部署步骤和后台管理)

本文还有配套的精品资源,点击获取

简介:这个毕业设计项目是一个开箱即用的电商购物系统,后端用Django REST Framework开发API,前端用Vue实现页面交互,前后端完全分离。功能覆盖商品分类展示、轮播图配置、用户留言、购物车操作、订单生成与状态管理等典型电商流程。数据库采用SQLite,附带两个Python脚本(import_category_data.py和import_goods_data.py)一键导入测试用的商品和分类数据,避免手动建表填数据。本地运行简单:后端执行python manage.py runserver,前端安装依赖后运行npm run serve即可调试。项目集成xadmin后台管理界面,支持商品、订单、用户等内容维护;内置DjangoUeditor富文本编辑器,方便后台发布图文内容;还预留social_core扩展接口,便于后续接入微信、QQ等第三方登录。所有代码经过本地环境验证,配套有README.md说明文档、目录结构解释和常见问题解答,适合计算机类专业本科生直接用于毕业设计、课程设计或实训开发。静态资源、媒体文件、模板路径都已按标准Django+Vue协作方式组织,结构清晰,模块职责明确,也方便在此基础上增删功能。

1. 这不是“又一个Demo”,而是一套能跑通电商全链路的毕业设计脚本

我带过六届本科生毕设,每年都有至少二十个同学卡在“前后端联调失败”“数据导入报错”“xadmin进不去后台”“Vue路由404”这几个坑里反复横跳。他们不是不会写代码,而是缺一套真正“从下载到部署”全程可验证、每一步都踩过坑、每个报错都有对应解法的完整闭环方案。这套 Django REST + Vue 的电商系统,就是我去年帮三个学生从开题答辩一路推到答辩现场的实战产物——它不追求炫技,但每一个模块都经过真实购物行为路径验证:用户从首页轮播图点击进入商品详情页 → 加入购物车 → 填写收货地址 → 提交订单 → 后台看到新订单并更新状态 → 用户收到微信通知(模拟)→ 管理员在 xadmin 中导出订单 Excel。整个流程跑下来,数据库事务没丢一条记录,前端状态没错一次,API 返回字段和文档完全一致。

关键词里写的“Django”“VUE”“电商系统”“毕业设计”“前后端分离”,不是标签堆砌,而是五个必须同时满足的硬约束。Django 不是随便选的——它自带 Admin、ORM、中间件、信号机制,对本科生最友好的地方在于:你改一行 model 字段,迁移命令自动生成 SQL,不用手写建表语句;Vue 也不是图新鲜——它的响应式原理和组件化结构,让“购物车数量实时变化”“分类菜单动态展开”这种交互逻辑,写起来比 jQuery 少一半代码、调试时间少三分之二;所谓“电商系统”,意味着不能只有商品列表,必须包含库存扣减的原子性控制(我们用select_for_update实现)、订单号防重生成(时间戳+随机数+用户ID哈希)、支付状态机(待支付→已支付→已发货→已完成→已退款);“毕业设计”这个定位决定了它必须有清晰的论文支撑点:比如 DRF 的权限控制如何分级(游客/登录用户/管理员),Vue 的路由守卫怎么拦截未登录访问,xadmin 的插件机制怎么扩展导出功能;而“前后端分离”不是口号——它体现在目录结构上:后端只管/api/开头的 JSON 接口,前端所有页面由 Vue Router 渲染,静态资源走 Nginx 静态服务,连跨域问题都用 Django 的django-cors-headers插件标准化解决,而不是靠浏览器插件临时绕过。

你拿到的不是一个 ZIP 包,而是一份可执行的开发剧本。里面import_category_data.py脚本不是简单插入几条测试数据,它会先清空旧分类、重建树形结构(用mptt模型实现无限级分类)、自动补全levellft/rght字段;import_goods_data.py更是把图片下载、缩略图生成、SKU 组合计算、库存初始化全部打包进一个函数里——你双击运行,58 秒后,后台就能看到 32 个一级分类、197 个二级分类、2648 件商品(含多规格 SKU)、12 张轮播图、47 条用户留言,全部带真实图片和描述。这不是 demo 数据,这是按淘宝“女装>连衣裙>碎花”三级类目逻辑构造的真实业务数据集。接下来我会带你一帧一帧拆解这个剧本:为什么选 SQLite 而不是 MySQL(不是偷懒,是规避毕设环境部署雷区);为什么 xadmin 替代原生 admin(它支持富文本字段一键嵌入、列表页批量操作按钮自定义、搜索框支持多字段模糊匹配);Vue 前端如何用vuex-persistedstate插件让购物车关掉浏览器也不丢数据;以及最关键的——当你的导师问“这个订单状态流转怎么保证不出现脏数据”,你怎么指着Order模型里的status字段和配套的transition方法,说出事务隔离级别和乐观锁的落地细节。

2. 整体架构设计与技术选型深挖

2.1 为什么坚持用 SQLite?这背后是毕设场景的生存智慧

很多同学第一反应是:“电商系统还用 SQLite?太假了!”——这话放在生产环境完全正确,但放在本科毕设场景里,恰恰是最高明的选择。我来算一笔账:如果你用 MySQL,光是本地环境搭建就要卡住至少三类人:第一类是 Mac M1/M2 芯片用户,Homebrew 安装 MySQL 8.0.33 时会遇到 ARM 架构兼容性问题,mysql.sock路径错乱导致 Django 连不上;第二类是 Windows 用户,安装 MySQL Installer 后默认勾选了 8GB 内存占用的“MySQL Router”,结果电脑直接卡死,重装系统;第三类是实验室机房电脑,管理员禁用了所有服务安装权限,你连mysqld进程都起不来。而 SQLite 是什么?它就是一个.sqlite3文件,Django 默认支持,settings.py里两行配置搞定:

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }

没有端口冲突,没有用户密码,没有服务进程管理,python manage.py migrate直接建库建表。更重要的是,SQLite 的 ACID 特性在单机场景下完全够用:我们的订单创建流程是典型的“三步事务”——扣减库存、生成订单主表、生成订单明细表。Django 的transaction.atomic()在 SQLite 上能完美保证这三步要么全成功、要么全回滚。我实测过并发 50 个用户同时下单,库存扣减零超卖(用select_for_update()锁住商品行)。当然,它也有明确边界:不支持全文检索(所以我们没做商品搜索高亮)、不支持在线 DDL(所以新增字段必须停服迁移)、最大文件尺寸 140TB 理论值虽高,但毕设数据量压根碰不到——你导入全部测试数据后,db.sqlite3文件才 28MB。

那如果导师质疑“不符合生产实际”怎么办?我的应答话术是:“SQLite 是我们验证业务逻辑的‘数字沙盒’。所有模型关系、状态机、权限控制、API 接口契约,都在 SQLite 上 100% 跑通。当需要迁移到 MySQL 或 PostgreSQL 时,只需修改DATABASES配置、运行python manage.py migrate,其余代码零修改——因为 Django ORM 屏蔽了底层差异。这正是分层架构的价值:数据访问层与业务逻辑层解耦。”

2.2 xadmin 替代原生 admin:不只是界面美化,而是生产力革命

Django 自带的 admin 后台,对毕设而言有两个致命短板:一是富文本编辑器缺失,商品详情页需要图文混排,原生 admin 只能贴纯文本或 HTML 源码;二是列表页功能简陋,无法按“订单状态+创建时间”组合筛选,导出按钮只支持 CSV,而导师要求看 Excel 格式报表。xadmin 正是为解决这两个痛点而生。

它不是简单换皮肤,而是重构了 admin 的扩展机制。核心在于xadmin.plugins插件体系:export插件接管导出逻辑,把queryset转成openpyxl.Workbook对象,自动适配中文列名;filters插件支持DateRangeFilter(时间范围筛选)、RelatedFieldFilter(关联字段筛选);最关键是ueditor插件,它把DjangoUeditor富文本编辑器无缝集成进字段表单。你在xadminGoodsAdmin类里这样写:

class GoodsAdmin(object): list_display = ['name', 'category', 'market_price', 'shop_price', 'goods_desc'] style_fields = {'goods_desc': 'ueditor'} # 关键!这一行让 goods_desc 字段变成富文本编辑器 search_fields = ['name', 'goods_brief'] list_filter = ['category', 'is_hot', 'add_time']

效果是:后台编辑商品时,“商品详情”字段不再是 textarea,而是带加粗/斜体/插入图片/表格的完整编辑器,上传的图片自动存到media/ueditor/目录,并生成<img src="/media/ueditor/xxx.jpg">标签。这直接省去学生手动拼 HTML 的时间,也让导师看到“后台内容管理能力”时眼前一亮。

但 xadmin 有坑:它不兼容 Django 4.x 的新中间件语法。项目里已打补丁——在extra_apps/xadmin/views/base.py中,把process_request方法里的request.user.is_authenticated()改为hasattr(request, 'user') and request.user.is_authenticated,避免AnonymousUser对象调用is_authenticated报错。这个细节,文档里不会写,但你运行时一定会遇到。

2.3 Vue 前端为何放弃 Vue CLI 官方脚手架?直面毕设部署的物理限制

官方 Vue CLI 生成的项目,默认npm run serve启动开发服务器,npm run build打包成dist/目录。但毕设答辩有个残酷现实:你得把整个项目拷贝到导师电脑上现场演示。如果前端是独立 Node.js 服务,导师电脑没装 Node 环境,npm install就可能失败(网络问题、镜像源失效、Python 版本不匹配)。所以我们采用“Django 静态服务托管 Vue”的混合模式。

具体做法:Vue 项目不单独部署,而是把npm run build生成的dist/目录,整体复制到 Django 的static/目录下;Django 的urls.py添加一条路由:

from django.views.generic import TemplateView urlpatterns += [ re_path(r'^.*$', TemplateView.as_view(template_name='index.html'), name='vue-app'), ]

这意味着:所有非/api/开头的请求(如/cart,/order),Django 都返回templates/index.html,由 Vue Router 在前端接管路由。index.html里引用的 JS/CSS 文件,路径指向/static/js/app.xxx.js,由 Django 的staticfiles服务提供。这样导师电脑只要装了 Python 3.8+,python manage.py runserver一条命令,前后端就全起来了——前端静态资源走 Django,后端 API 走 Django,端口统一为 8000,彻底消灭跨域和环境依赖。

这个方案牺牲了 Vue DevTools 的热重载,但换来的是 100% 的可移植性。我在三个不同学院的答辩现场验证过:MacBook Air、Windows 笔记本、Linux 虚拟机,只要 Python 环境正常,git clonepip install -r requirements.txt && python manage.py migrate && python manage.py runserver,打开浏览器就能看到完整的电商首页。这才是毕设该有的鲁棒性。

2.4 social_core 第三方登录:预留接口,而非强行接入

项目里提到social_core,但它在代码中其实是“半激活”状态。为什么?因为微信/QQ 登录需要申请开发者资质、配置回调域名、HTTPS 证书——这些对本科生来说,是远超毕设范畴的工程成本。但我们预留了完整接入路径:

  • 后端:settings.py中已配置AUTHENTICATION_BACKENDS,包含social_core.backends.weibo.WeiboOAuth2等后端;
  • 前端:src/api/login.js里留有loginWithWeibo()函数骨架,调用/api/auth/weibo/login/接口;
  • 数据库:UserSocialAuth模型已通过 migration 创建。

真正的接入,只需三步:第一步,在微信开放平台创建网站应用,获取APP_IDAPP_SECRET;第二步,把密钥填进settings.pySOCIAL_AUTH_WEIBO_KEY;第三步,前端在登录页加一个“微信图标”按钮,绑定loginWithWeibo()。整个过程不改动核心业务逻辑,所有社交登录用户,最终都映射到 Django 的User模型,订单、购物车等数据完全复用。这是一种“面向未来的设计”:你现在可以只做账号密码登录,答辩时导师问“如果要加微信登录怎么办”,你就能指着代码说:“这里已经预留好钩子,两天内就能上线。”

3. 核心模块实现与关键细节解析

3.1 商品分类与轮播图:用 MPTT 实现无限级分类的底层逻辑

电商系统的分类管理,绝不是简单的“父ID”外键能搞定的。当分类达到三级甚至四级(如“手机>苹果>iPhone 15>Pro Max”),查询“苹果下所有手机”就需要递归查询,性能极差。项目采用django-mptt库实现改进的预排序遍历树算法(Modified Preorder Tree Traversal),核心是给每个节点增加lft(左值)、rght(右值)、level(层级)、tree_id(树ID)四个字段。

apps/goods/models.py中的Category模型:

from mptt.models import MPTTModel, TreeForeignKey class Category(MPTTModel): name = models.CharField('类别名', max_length=30, default="") code = models.CharField('类别code', max_length=30, default="") desc = models.TextField('类别描述', default="") category_type = models.IntegerField('类目级别', choices=((1, "一级"), (2, "二级"), (3, "三级"))) parent_category = TreeForeignKey('self', null=True, blank=True, verbose_name="父类目", related_name="sub_cat", on_delete=models.CASCADE) is_tab = models.BooleanField('是否导航', default=False) add_time = models.DateTimeField('添加时间', default=datetime.now) class MPTTMeta: order_insertion_by = ['name'] # 新节点按名称字母序插入

关键在MPTTMeta类——它告诉mptt如何维护树结构。当你执行Category.objects.create(name="连衣裙", parent_category=Category.objects.get(name="女装"))mptt会自动计算并写入lft/rght值。查询“女装下的所有子分类”变得极其高效:

# 获取“女装”节点 women_category = Category.objects.get(name="女装") # 查询其所有后代(含自身),一行代码搞定,无需递归 sub_categories = women_category.get_descendants(include_self=True)

get_descendants()底层执行的是SELECT * FROM goods_category WHERE lft BETWEEN ? AND ? AND tree_id = ?,时间复杂度 O(1)。而轮播图Banner模型则与Category关联,通过category外键实现“某分类专属轮播”:

class Banner(models.Model): title = models.CharField("标题", max_length=100, default="") image = models.ImageField("轮播图", upload_to="banner/", max_length=200) url = models.URLField("访问地址", max_length=200, default="") category = models.ForeignKey(Category, verbose_name="商品分类", null=True, blank=True, on_delete=models.CASCADE) index = models.IntegerField("轮播顺序", default=0) add_time = models.DateTimeField("添加时间", default=datetime.now)

这样,首页轮播图可以展示全站通用 Banner,而“女装”分类页则展示category字段指向“女装”的 Banner,数据隔离清晰。import_category_data.py脚本在导入时,会先按level排序,确保父节点一定在子节点之前创建,避免parent_category外键为空报错。

3.2 购物车与订单:状态机驱动的事务安全设计

购物车和订单是电商最易出错的模块。常见错误包括:库存扣减后订单创建失败导致库存“幽灵锁定”、同一用户多次点击提交生成重复订单、优惠券使用后未校验库存是否充足。我们的解决方案是“状态机 + 事务 + 幂等”。

先看购物车ShopCart模型:

class ShopCart(models.Model): user = models.ForeignKey(User, verbose_name="用户", on_delete=models.CASCADE) goods = models.ForeignKey(Goods, verbose_name="商品", on_delete=models.CASCADE) nums = models.IntegerField("购买数量", default=0) add_time = models.DateTimeField("添加时间", default=datetime.now) class Meta: unique_together = ("user", "goods") # 关键!强制用户-商品唯一,避免重复记录

unique_together是第一道防线:同一个用户对同一商品,只能有一条购物车记录。前端点击“+”时,后端不是create(),而是update_or_create()

def add_to_cart(request): user = request.user goods_id = request.data.get('goods_id') nums = request.data.get('nums', 1) cart_item, created = ShopCart.objects.update_or_create( user=user, goods_id=goods_id, defaults={'nums': nums} # 如果存在,就更新 nums;不存在,就创建 ) return Response({"success": True})

订单OrderInfo模型则用status字段实现状态机:

class OrderInfo(models.Model): ORDER_STATUS = ( ("TRADE_SUCCESS", "成功"), ("TRADE_CLOSED", "超时关闭"), ("WAIT_BUYER_PAY", "交易创建"), ("TRADE_FINISHED", "交易完成"), ("paying", "待支付"), ) user = models.ForeignKey(User, verbose_name="用户", on_delete=models.CASCADE) order_sn = models.CharField("订单号", max_length=30, unique=True) trade_no = models.CharField("交易号", max_length=100, unique=True, blank=True, null=True) pay_status = models.CharField("订单状态", choices=ORDER_STATUS, default="paying", max_length=30) post_script = models.CharField("订单留言", max_length=200) order_mount = models.FloatField("订单金额") pay_time = models.DateTimeField("支付时间", null=True, blank=True) # ... 其他地址、商品明细字段

创建订单的核心逻辑在apps/trade/views.pyOrderViewset中:

@action(methods=['post'], detail=False) def make_order(self, request): with transaction.atomic(): # 开启事务 # 1. 锁定购物车商品,防止并发扣减 cart_items = ShopCart.objects.select_for_update().filter( user=request.user, id__in=request.data.get('cart_ids', []) ) # 2. 检查库存(此处省略详细校验逻辑) for item in cart_items: if item.goods.goods_num < item.nums: raise ValidationError(f"商品 {item.goods.name} 库存不足") # 3. 扣减库存(原子操作) for item in cart_items: Goods.objects.filter(id=item.goods.id).update( goods_num=F('goods_num') - item.nums ) # 4. 创建订单主表 order = OrderInfo.objects.create( user=request.user, order_sn=generate_order_sn(), # 时间戳+用户ID哈希 order_mount=sum(item.goods.shop_price * item.nums for item in cart_items), # ... 其他字段 ) # 5. 创建订单明细 for item in cart_items: OrderGoods.objects.create( order=order, goods=item.goods, goods_num=item.nums, goods_price=item.goods.shop_price ) # 6. 清空购物车 cart_items.delete() return Response({"order_sn": order.order_sn})

select_for_update()是关键——它在数据库层面给选中的购物车记录加行锁,确保同一商品不会被两个请求同时扣减。generate_order_sn()函数生成唯一订单号:

def generate_order_sn(): # 当前时间 + 用户ID + 随机数,保证全局唯一且不可预测 from random import Random random_ins = Random() order_sn = "{time_str}{userid}{ranstr}".format( time_str=time.strftime("%Y%m%d%H%M%S"), userid=request.user.id, ranstr=random_ins.randint(10, 99) ) return order_sn

这个设计经受住了 100 并发下单压力测试:无重复订单、无超卖、事务回滚后购物车数据完好。

3.3 用户留言与后台富文本:DjangoUeditor 的深度定制

用户留言UserLeavingMessage模型需要支持图片上传,原生TextField只能存文字。DjangoUeditor提供了完整的富文本解决方案,但默认配置不满足毕设需求:上传图片默认存到media/ueditor/,但我们需要按日期分目录(避免单目录文件过多),且需限制图片大小。

定制在extra_apps/DjangoUeditor/ueditor_settings.py中:

UEDITOR_SETTINGS = { "config": { "imageUrlPrefix": "/media", # 图片 URL 前缀 "imagePathFormat": "/ueditor/image/{yyyy}{mm}{dd}/{time}{rand:6}", # 上传路径格式 }, "upload": { "imageMaxSize": 2048000, # 2MB "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], } }

imagePathFormat中的{yyyy}{mm}{dd}会自动替换成当前日期,例如20240520{time}{rand:6}是毫秒时间戳加6位随机数,彻底避免文件名冲突。前端UserLeavingMessage表单使用UEditorField

from DjangoUeditor.models import UEditorField class UserLeavingMessage(models.Model): MESSAGE_CHOICES = ( (1, "留言"), (2, "投诉"), (3, "咨询"), (4, "售后"), (5, "求购"), ) subject = models.CharField("主题", max_length=100, default="") message_type = models.IntegerField("留言类型", choices=MESSAGE_CHOICES, default=1) message = UEditorField('留言内容', width=1000, height=300, toolbars="full", imagePath="ueditor/image/", filePath="ueditor/file/", upload_settings={"imageMaxSize": 2048000}, default='') file = models.FileField("上传附件", upload_to="message/files/", null=True, blank=True) add_time = models.DateTimeField("添加时间", default=datetime.now)

UEditorField会自动渲染富文本编辑器,并处理图片上传逻辑。xadmin后台中,UserLeavingMessageAdmin类启用style_fields = {'message': 'ueditor'},即可在后台直接编辑带图留言。这个细节让“用户互动模块”不再是纯文字,而是具备真实电商客服场景的图文反馈能力。

4. 实操全流程与部署避坑指南

4.1 从零开始:10 分钟完成本地环境搭建

别被目录树吓到,真正需要你操作的只有 5 个步骤。我以 Windows 10 + Python 3.9 为例(Mac/Linux 命令仅路径分隔符不同):

步骤 1:解压与进入目录
下载171265889347208773632.zip,解压到任意盘符(如D:\project\)。打开命令行,进入MxShopV2目录:

cd D:\project\MxShopV2

步骤 2:创建虚拟环境(强烈推荐)
避免污染全局 Python 环境:

python -m venv venv venv\Scripts\activate.bat # Windows # Mac/Linux 用:source venv/bin/activate

步骤 3:安装后端依赖
requirements.txt已锁定所有版本,确保环境一致:

pip install -r requirements.txt

注意:如果报Microsoft Visual C++ 14.0 is required错误,去微软官网下载Build Tools for Visual Studio,或直接pip install --only-binary=all django-mptt跳过编译。

步骤 4:初始化数据库与导入数据

python manage.py makemigrations python manage.py migrate python db_tools/import_category_data.py # 导入分类,约 8 秒 python db_tools/import_goods_data.py # 导入商品,约 58 秒(含图片下载)

import_goods_data.py会自动从images/目录读取商品图片,若提示No module named 'PIL',执行pip install Pillow

步骤 5:启动后端服务

python manage.py runserver

此时访问http://127.0.0.1:8000/api/,能看到 DRF 的 API Root 页面,说明后端已就绪。

前端启动(无需 Node.js)
如前所述,前端已打包进static/。直接访问http://127.0.0.1:8000/即可看到首页。若页面空白,检查浏览器控制台是否有Failed to load resource: the server responded with a status of 404 (Not Found)错误——这通常是因为static/目录未正确复制。请确认MxShopV2/static/js/下存在app.xxx.js文件(文件名带哈希值)。

4.2 xadmin 后台登录:解决“用户名密码错误”的三大原因

运行python manage.py runserver后,访问http://127.0.0.1:8000/xadmin/,输入默认账号admin/admin123却提示错误?别急,90% 是以下原因:

原因一:数据库未迁移,xadmin 表缺失
执行python manage.py migrate后,检查db.sqlite3文件是否生成。用 DB Browser for SQLite 打开,查看auth_user表是否有admin记录。若无,手动创建:

python manage.py createsuperuser # 按提示输入用户名(如 admin)、邮箱、密码

原因二:xadmin 配置未加载
检查MxShopV2/settings.py中是否包含:

INSTALLED_APPS = [ # ... 其他 app 'xadmin', 'crispy_forms', 'reversion', ]

以及urls.py中是否注册了 xadmin 路由:

import xadmin xadmin.autodiscover() urlpatterns = [ path('xadmin/', xadmin.site.urls), # ... 其他路由 ]

原因三:密码加密方式不匹配(最隐蔽)
Django 2.0+ 默认用 PBKDF2 算法加密密码,但某些旧版 xadmin 插件可能用 MD5。解决方案:重置密码。

python manage.py changepassword admin # 输入新密码两次

4.3 前端路由 404:Vue Router 的 history 模式陷阱

访问http://127.0.0.1:8000/cart显示 Django 的 404 页面?这是 Vue Router 的history模式导致的。Vue Router 默认用history.pushState()改变 URL,但 Django 不认识/cart这个路径,它只认/api/开头的 API 路由。

解决方案已在urls.py中预置:

from django.views.generic import TemplateView urlpatterns += [ re_path(r'^.*$', TemplateView.as_view(template_name='index.html'), name='vue-app'), ]

但此规则必须放在所有其他path()规则之后!检查你的urls.py,确保re_path(r'^.*$'...)是最后一个路由。否则,/api/请求也会被它捕获,返回index.html而不是 JSON。

4.4 部署到云服务器:Nginx + Gunicorn 最简配置

毕设答辩常需外网演示,推荐腾讯云轻量应用服务器(2核2G,首年 99 元)。部署只需四步:

1. 安装基础环境

sudo apt update sudo apt install python3-pip python3-dev nginx git sudo pip3 install gunicorn

2. 上传代码并安装依赖

git clone your-repo-url /home/ubuntu/MxShopV2 cd /home/ubuntu/MxShopV2 sudo pip3 install -r requirements.txt

3. 配置 Gunicorn
创建/etc/systemd/system/gunicorn.service

[Unit] Description=gunicorn daemon After=network.target [Service] User=ubuntu Group=www-data WorkingDirectory=/home/ubuntu/MxShopV2 ExecStart=/usr/local/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/MxShopV2/mxshop.sock MxShopV2.wsgi:application [Install] WantedBy=multi-user.target

启动:sudo systemctl start gunicorn && sudo systemctl enable gunicorn

4. 配置 Nginx
编辑/etc/nginx/sites-available/mxshop

server { listen 80; server_name your-domain.com; location /static/ { alias /home/ubuntu/MxShopV2/static/; } location /media/ { alias /home/ubuntu/MxShopV2/media/; } location / { include proxy_params; proxy_pass http://unix:/home/ubuntu/MxShopV2/mxshop.sock; } }

启用:sudo ln -sf /etc/nginx/sites-available/mxshop /etc/nginx/sites-enabled && sudo nginx -t && sudo systemctl restart nginx

此时访问http://your-domain.com,即可看到线上电商系统。整个过程无需修改一行业务代码。

5. 常见问题与排查技巧实录

5.1 数据导入脚本报错:requests.exceptions.ConnectionError

现象:运行python db_tools/import_goods_data.py时,报错ConnectionError: HTTPConnectionPool(host='p0.meituan.net', port=80): Max retries exceeded...

原因:脚本尝试从美团图片 CDN 下载商品图,但国内网络不稳定或 CDN 域名已变更。

解决方案:离线模式。脚本已内置开关:

# 在 import_goods_data.py 开头,找到这行并改为 True DOWNLOAD_IMAGES = False # 默认为 True,改为 False 即跳过下载

然后将images/目录下的所有图片,手动复制到media/goods/images/目录。import_goods_data.py会优先读取本地图片。

5.2 前端显示“Network Error”:跨域问题的终极诊断法

当 Vue 控制台报Network Error,但后端http://127.0.0.1:8000/api/goods/能正常访问,一定是跨域配置问题。

三步诊断法:
1.查请求头:在浏览器 Network 面板,点击报错的 API 请求,看 Request Headers 是否有Origin: http://localhost:8080(Vue CLI 默认端口);
2.查响应头:看 Response Headers 是否有Access-Control-Allow-Origin: *
3.查 Django 设置:确认settings.py中:
python INSTALLED_APPS += ['corsheaders'] MIDDLEWARE.insert(0, 'corsheaders.middleware.CorsMiddleware') CORS_ALLOW_ALL_ORIGINS = True # 开发阶段允许所有来源 # 或更安全的:CORS_ALLOWED_ORIGINS = ["http://localhost:8080"]

如果第 2 步没看到响应头,说明corsheaders未生效,检查MIDDLEWARE顺序——CorsMiddleware必须在CommonMiddleware之前。

5.3 xadmin 列表页空白:JavaScript 加载失败的静默崩溃

进入http://127.0.0.1:8000/xadmin/,左侧菜单正常,但右侧列表区域一片空白,控制台无报错?

这是 xadmin 的xadmin.js加载失败的典型表现。原因通常是STATIC_URL配置错误。检查settings.py

STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') # 注意:不是 static/

STATIC_ROOTcollectstatic命令收集静态文件的目标目录,而STATICFILES_DIRS才是源目录:

STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ]

运行python manage.py collectstatic --noinput,确保staticfiles/xadmin/下有xadmin.js文件。若无,说明STATICFILES_DIRS路径写错。

5.4 订单状态不更新:Celery 异步任务未启动(但本项目未启用)

等等,项目里根本没装 Celery!这是故意为之的“防坑设计”。很多毕设盲目加入 Celery 处理异步任务,结果卡在 Redis 安装、broker 配置、worker 启动上。我们的订单状态更新全部同步完成:支付成功回调(模拟)直接调用OrderInfo.objects.filter(order_sn=sn).update(pay_status="TRADE_SUCCESS", pay_time=now)。若你看到状态不更新,请检查:
- 回调接口/api/order/callback/是否被 CSRF 中间件拦截?在视图类上加@csrf_exempt
-pay_status字段值是否拼写错误?DRF 序列化器中choices"TRADE_SUCCESS",不是"success"

5.5 毕设答辩高频问题应答锦囊

Q:为什么用 Django REST Framework 而不是 Flask?
A:“Flask 更轻量,但毕设需要快速构建健壮的 API。DRF 提供了开箱即用的认证(TokenAuthentication)、权限(IsAuthenticated)、序列化(Serializer 验证字段类型和必填)、分页(PageNumberPagination)、文档生成(SchemaGenerator),这些模块在 Flask 中需要自己组合多个扩展,学习成本反而更高。我们用 DRF 三天就完成了全部 API,而 Flask 同学还在调试 JWT token 解析。”

Q:Vue 前端如何保证 XSS 安全?
A:“所有用户输入内容,后端在保存前用html.escape()转义特殊字符;前端展示时,Vue 模板语法{{ content }}默认进行 HTML 转义,只有显式使用v-html才会渲染 HTML。我们在商品详情、用户留言等富文本字段,严格区分:后台编辑用DjangoUeditor(它自带 XSS 过滤),前端展示用v-html但配合DOMPurify库二次净化,确保只允许<p><img><strong>等安全标签。”

Q:这个系统如何体现‘软件工程’专业特色?
A:“体现在三个层次:第一,过程规范——我们用 Git 分支管理(main 为稳定版,dev 为开发版,feature/xxx 为功能分支),每次 commit 有清晰 message;第二,质量保障——所有 API 接口编写了 DRF 的APITestCase单元测试,覆盖商品查询、购物车增删、订单创建等核心路径;第三,可维护性——模块划分严格遵循‘高内聚低耦合’,apps/goods/只处理商品相关逻辑,apps/trade/只处理交易,apps/user/只处理用户,彼此通过 signals 或 service 层通信,便于后续替换某个模块而不影响全局。”

最后再分享一个小技巧:答辩前夜,务必在导师电脑上实测一次。带上一个装好 Python 3.9 的 U 盘,现场git clonepip installpython manage.py runserver,把整个流程走一遍。当导师看到你 3 分钟内就让系统跑起来,眼神里的怀疑会立刻变成赞许——因为这证明你不是纸上谈兵,而是真正掌控了从代码到运行的每一环。

本文还有配套的精品资源,点击获取

简介:这个毕业设计项目是一个开箱即用的电商购物系统,后端用Django REST Framework开发API,前端用Vue实现页面交互,前后端完全分离。功能覆盖商品分类展示、轮播图配置、用户留言、购物车操作、订单生成与状态管理等典型电商流程。数据库采用SQLite,附带两个Python脚本(import_category_data.py和import_goods_data.py)一键导入测试用的商品和分类数据,避免手动建表填数据。本地运行简单:后端执行python manage.py runserver,前端安装依赖后运行npm run serve即可调试。项目集成xadmin后台管理界面,支持商品、订单、用户等内容维护;内置DjangoUeditor富文本编辑器,方便后台发布图文内容;还预留social_core扩展接口,便于后续接入微信、QQ等第三方登录。所有代码经过本地环境验证,配套有README.md说明文档、目录结构解释和常见问题解答,适合计算机类专业本科生直接用于毕业设计、课程设计或实训开发。静态资源、媒体文件、模板路径都已按标准Django+Vue协作方式组织,结构清晰,模块职责明确,也方便在此基础上增删功能。


本文还有配套的精品资源,点击获取

http://www.zskr.cn/news/1485967.html

相关文章:

  • 嵌入式信号处理避坑指南:你的滤波器阶数真的选对了吗?
  • COM3D2 MaidFiddler终极指南:实时修改女仆属性的完整教程
  • 深入解析FPGA架构:从查找表到逻辑单元与布线资源
  • ZYNQ开发者效率翻倍:VSCode插件全攻略(从Testbench生成到TCL语法高亮)
  • YOLO-FastestV2模型训练与NCNN端侧部署实战:从自制数据集到手机端300FPS推理
  • DeTikZify:AI驱动的科学图表自动TikZ代码生成解决方案
  • 汇川PLC变量定义避坑指南:从局部变量、全局变量到掉电保持,一次讲清
  • AI知识库效率提升10倍:从衡量指标到数据准备的完整决策框架
  • 工业级遗传算法调优实战:解决早熟收敛与业务约束建模
  • 70+插件一键解锁:AI-Shoujo HF Patch终极增强方案
  • PotatoNV免费解锁华为Bootloader完整指南:开源工具与付费方案的终极对比
  • QQ音乐加密文件转换终极指南:3步解锁你的音乐收藏
  • 从 MVP 到规模化:项目管理中的技术取舍与节奏控制
  • ViGEmBus虚拟游戏控制器驱动:终极完整指南与5步快速上手教程
  • 30人以下初创团队福音:手把手教你免费申请腾讯Tapd企业版(附企业微信绑定全流程)
  • 如何高效管理PS3游戏更新:从官方服务器直连下载到智能批量处理
  • Sunshine游戏串流完整指南:5步搭建你的个人云游戏服务器
  • 2026 年 6 月福州高考志愿填报怎么选?避开滑档与分数浪费 - 讲清楚了
  • Tableau蓝绿pill本质:数据语义与分析范式的底层逻辑
  • 南京家电回收 - 资讯快报
  • 从大厂到创业:技术架构的降级与重构策略
  • 德宏傣族景颇族自治州2026年黄金回收白银回收铂金回收 5 家高性价比门店实地测评盘点 - 马刺总冠军
  • 德阳市2026年黄金回收白银回收铂金回收 5 家高性价比门店实地测评盘点 - 马刺总冠军
  • 别只刷题了!蓝桥杯备赛,用好‘真题水题’和‘分组机制’这两张王牌
  • 2026相变冷却液品牌排名:全国五大厂家选购指南 - 品研笔录
  • 科研信息流操作系统:从论文筛选到知识资产化的工程化实践
  • 十堰市2026年黄金回收白银回收铂金回收 5 家高性价比门店实地测评盘点 - 奢金阁
  • 2026在线去水印工具有哪些?好用的去水印工具推荐指南 - 科技热点发布
  • Rhino浮动许可调度模式,4家谁最省心
  • 【Kafka源码解读和使用指南】第15篇:Kafka集群元数据源码解析——生产者如何“认识“整个集群