news 2026/10/4 5:44:47

Django+MySQL商城毕设源码:从环境搭建到答辩全流程拆解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Django+MySQL商城毕设源码:从环境搭建到答辩全流程拆解

简介:这是一份基于Python的购物商城管理系统完整毕业设计项目,包含可运行源码与配套数据库,专为计算机相关专业毕业生准备,也适合课程设计、期末大作业或有Python基础的实战练习者使用。压缩包共384个文件、约15.8MB,核心由94个.py源码、59个.html页面及配套CSS/JS/XML配置组成,另含3份.sql数据库脚本便于建表,141张JPG与33张PNG图片用作商品及界面素材,还附有“蔬果优选”项目开发过程与架构概述docx文档;文件按模块归置,结构清楚,便于快速定位。该项目评审分98分,源码经本地编译调试可运行,商品展示、购物车、订单处理等电商关键模块均有完整代码支撑,数据库脚本可省去手工建表步骤,直接作为毕业设计蓝本或二次开发基础。目前已有239人学习下载,是一套实用价值较高的Python商城学习资源。

1. 一份Python商城毕设源码,打开之后你到底拿到了什么?

搜到「基于Python的购物商城管理系统源码+数据库(毕业设计).zip」这个标题的人,多数是两种处境:一种已经把压缩包解压,面对manage.py、models.py和几个.sql文件,不知道下一步点哪里;另一种是刚拿到毕设题目,想找一条能走到答辩的稳妥路线。标题本身说明白了交付物——一套Python写的商城前后台源码、一份能恢复的数据库、以及安装运行的方法。这里面的关键点不在“代码能不能抄”,而在你能不能在本机把服务跑起来、把数据导进去、把用户侧和管理侧两条链路讲清楚。这篇笔记按这个顺序拆:先定技术栈,再建数据库,然后走核心业务代码,最后把最容易翻车的地方和答辩前的验收路径给你摆出来。

2. 先把技术栈拆清楚:Django + MySQL的组合为什么是毕设默认答案?

在这套毕设源码里,Python是语言,而商城Web服务需要一个Web框架。常看到的组合是Django + MySQL,少数用Flask + SQLite。MySQL几乎是这类毕业设计事实上的标准数据库,因为题目里写了“数据库”两个字,老师在答辩时第一句往往就是“你的数据放在哪里、怎么保证一致性”。Django在这条路上的优势,不只是写起来快,更是它把商城管理系统里最重的“管理后台”部分替你完成了一半。

2.1 Django Admin、ORM和认证:商城里的“管理系统”一半是白送的

先看“管理系统”四个字落在哪。一个购物商城管理系统,用户侧是注册登录、商品浏览、加购下单;管理侧是商品上架下架、订单状态修改、会员信息查看。Django自带admin后台,只要把模型注册进去,增删改查界面就直接能用。我一般会这样把Product注册进Admin:

from django.contrib import admin from .models import Category, Product @admin.register(Product) class ProductAdmin(admin.ModelAdmin): list_display = ('id', 'name', 'category', 'price', 'stock', 'sales', 'is_on_sale') search_fields = ('name',) list_filter = ('is_on_sale', 'category') list_editable = ('price', 'stock', 'is_on_sale') list_per_page = 20

这段配置的效果是:登录/admin/后,商品列表直接显示id、名称、分类、价格、库存、销量、是否上架;右上角搜索框对商品名做模糊查找;左侧筛选器按上架状态和分类过滤;右侧列表页能直接改价格、库存和上架开关,不用点进编辑页。对毕业设计答辩来说,这四样东西恰好覆盖了“商品管理”最常见的演示动作。list_display、search_fields、list_filter是ModelAdmin最常用的三个属性,字段名必须与模型字段完全一致,否则会报FieldError;list_editable里的字段不能同时出现在list_display之外,否则会冲突。

ORM解决的是“数据库增删改查”怎么落到代码里的问题。不需要手写SQL,Product.objects.filter(is_on_sale=True)就是对shop_product表做条件查询,Product.objects.create(...)是插入。以后老师问起“数据库这一块怎么设计的”,你直接说“模型在models.py里,数据库表由migrate生成”,比背SQL语句要清晰得多。认证系统也自带:django.contrib.auth提供User模型、authenticate()、login()、logout()三个核心函数,注册、登录、会话保持的底层逻辑不需要自己造轮子。

如果用Flask,这些全部要自己拼:Flask-SQLAlchemy管理ORM、Flask-Login管理会话、Flask-Admin做管理后台,每一个都要额外配。灵活性是高,但对一个要在几周内出成果的毕设来说,Django把默认事情做完、把自由留给业务代码,是更稳妥的选择。管理后台这一层,光靠Django Admin就能演示掉“商品增删改查、订单状态修改”两块功能。

2.2 项目结构与依赖文件:clone下来第一件事是建虚拟环境装python依赖

拿到源码压缩包,别急着运行。我见过太多人直接在全局环境里执行pip install,结果全家桶版本冲突,最后连django都起不来。正确做法是每一个项目一套虚拟环境。先确认python安装没问题,再创建虚拟环境:

python --version # 建议 Python 3.8 以上,Django 4.x 才能跑 python -m venv venv # Windows 激活 venv\Scripts\activate # macOS / Linux 激活 source venv/bin/activate pip install -r requirements.txt

venv会在项目目录下生成一个独立Python环境,pip install的包只对这个项目生效。激活后命令行前缀会出现(venv),这时再装依赖就不会污染系统Python。requirements.txt是这套源码依赖的清单,一般长这样:

Django==4.2.7 PyMySQL==1.1.0 Pillow==10.1.0

Django是Web框架,PyMySQL是让Python连上MySQL的驱动,Pillow是处理商品图片上传必需的图像库。有些源码写的是mysqlclient而不是PyMySQL,mysqlclient在Windows上经常编译失败,踩过的人不少;如果环境装不上,我的习惯是改成PyMySQL,并在项目包入口做一次适配,这点在下一小节展开。装完依赖后,用pip list确认django已经在虚拟环境里。

注意:如果 pip 下载依赖太慢,可以在 install 命令后加国内PyPI镜像参数临时加速,装完不影响项目本身。

然后启动开发服务器:

python manage.py runserver 0.0.0.0:8000

0.0.0.0:8000表示监听所有网卡,这样能在局域网里用同一WiFi下的手机访问页面,答辩现场演示比只开127.0.0.1方便。能起服务只代表代码没语法错,真正决定能不能跑通的是settings.py配置,下面说三处必须过的。

2.3 settings.py必改的三处:数据库连接、媒体路径与密钥

settings.py是整套源码的配置文件。第一处是DATABASES,决定Django连哪个数据库。拿到源码后,里面可能是SQLite的默认配置,也可能是别人机器的MySQL账号密码,都需要改成你自己的:

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'shop_db', 'USER': 'root', 'PASSWORD': '你的mysql密码', 'HOST': '127.0.0.1', 'PORT': '3306', 'OPTIONS': { 'charset': 'utf8mb4', }, } }

NAME是数据库名,必须先在MySQL里建好。HOST和PORT一般保持127.0.0.1和3306,如果你的MySQL不是在默认端口,这里就要对上。OPTIONS里的charset=utf8mb4很关键,它保证中文正常读写,不然商品名和订单地址会变成乱码。

第二处是媒体文件配置。商品封面上传后Django把文件放在MEDIA_ROOT目录,通过MEDIA_URL路径访问:

MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

如果不配,最直观的翻车现象是首页商品图全部裂开、后台也看不到缩略图。第三处是SECRET_KEY。源码包里一般带了一个开发用密钥,能跑,但答辩前最好换掉,尤其如果这个包是网上多人下载的公开源码。生成办法是重启一个Django项目从里面复制,或者直接用secrets.token_hex(50)产出。这事不算必须,但属于最基本的收尾意识。

如果用的是PyMySQL替代mysqlclient,一定要在settings.py同级目录的__init__.py里加这两行:

import pymysql pymysql.install_as_MySQLdb()

不加这个,Django在连MySQL时会报“ModuleNotFoundError: No module named 'MySQLdb'”。install_as_MySQLdb()的作用是把PyMySQL伪装成MySQLdb接口,Django的mysql后端就能正常走通。这样配置完,服务能起来、库能连上,下一步就是把数据库表结构铺出来。

3. 数据库设计与初始化:六张表、一次migrate、一份必带演示数据

数据库设计是答辩时老师看得最仔细的部分。商城系统的最小闭环,围绕“用户、商品、购物车、订单”四个对象展开。加上分类与订单明细,一共六张核心表就够支撑整个演示流程。表结构设计得干净,后面写业务代码几乎不用回头改。

3.1 六张核心表的字段设计:从商品分类到订单明细

常见做法是每张表对应一个Django模型,模型定义在models.py,数据库表由迁移命令生成。先看表级设计:

表名作用关键字段
shop_category商品分类id, name, parent_id, sort_order
shop_product商品id, category_id, name, cover, price, stock, sales, is_on_sale, created_at
shop_cart购物车id, user_id, product_id, quantity
shop_order订单主表id, order_no, user_id, total_amount, status, address, created_at
shop_order_item订单明细id, order_id, product_id, product_name, price, quantity, subtotal
user_profile用户扩展信息id, user_id, phone, address

商品分类表用自关联parent_id支持一级、二级分类,毕设通常展示一级分类就够了,留这个字段是为了演示时可以再加子类。商品表的price字段用DecimalField(max_digits=10, decimal_places=2),金额不能存Float,浮点误差在订单结算时会被放大,这是基础规范。字段模型代码就是直接描述:

from django.db import models from django.contrib.auth.models import User class Category(models.Model): name = models.CharField(max_length=50, verbose_name='分类名') parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True) sort_order = models.IntegerField(default=0) class Meta: db_table = 'shop_category' class Product(models.Model): category = models.ForeignKey(Category, on_delete=models.PROTECT, verbose_name='所属分类') name = models.CharField(max_length=128, verbose_name='商品名') cover = models.ImageField(upload_to='goods/', null=True, blank=True, verbose_name='封面图') price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='售价') stock = models.IntegerField(default=0, verbose_name='库存') sales = models.IntegerField(default=0, verbose_name='销量') is_on_sale = models.BooleanField(default=True, verbose_name='是否上架') created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') class Meta: db_table = 'shop_product' ordering = ['-created_at']

这里产品分类外键用了on_delete=models.PROTECT,意思是分类被商品引用时禁止删除分类,防止商品变成无主孤魂。很多人会顺手写CASCADE,结果删分类把商品也删了,答辩演示时想恢复都难。这是一个细小但很能展示工程意识的点。

订单主表与订单明细为什么要拆两张表:一个订单可能有多个商品,每个商品有自己的数量、单价和行小计。主表只存订单总额、状态、收货地址,明细表存每一行。明细表里冗余了product_name、price快照,这是刻意的——下单后商品改名、改价都不影响订单历史数据的准确性。老师问“为什么要冗余”,这是个标准答案。

订单状态我习惯用整数字段加choices来做:

class Order(models.Model): STATUS_CHOICES = ( (1, '待付款'), (2, '已付款'), (3, '已发货'), (4, '已完成'), (5, '已取消'), ) order_no = models.CharField(max_length=32, unique=True, verbose_name='订单号') user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='下单用户') total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='订单总额') status = models.IntegerField(choices=STATUS_CHOICES, default=1, verbose_name='订单状态') address = models.CharField(max_length=255, verbose_name='收货地址') created_at = models.DateTimeField(auto_now_add=True) class Meta: db_table = 'shop_order'

状态机从1走到4,管理后台直接改数字下拉框,演示“发货”就是把状态从2改成3。order_no用时间戳加随机数生成,保证唯一。

3.2 从models.py到建表:makemigrations的正确打开方式

类定义好了,数据库里还没有表。Django的迁移机制分两步:makemigrations生成迁移脚本,migrate执行建表。

python manage.py makemigrations python manage.py migrate

第一次跑,会看到类似“Migrations for 'goods' 0001_initial.py”的输出,然后migrate把所有app的迁移都执行一遍,包括Django自带的auth、admin、session表。这一步成功之后,MySQL里执行SHOW TABLES;能看到django_开头的系统表和shop_开头的业务表。

以后要修改表结构,比如给Product加一个原价字段,正确路径是:改models.py → 再跑python manage.py makemigrations → 再跑migrate。不要直接在Navicat里改表,改完Django不知道,后面ORM一查询就报列不存在。MySQL数据库修改结构这件事,在Django项目里应当由迁移命令统一管理,这是源码能不能“换台机器也能跑”的根基。

如果makemigrations提示No changes detected,通常是app没有写进INSTALLED_APPS,或者models.py根本没import。如果migrate报错提示表已经存在,常见原因是别人把.sql文件和迁移混着用了。要么纯SQL导入,要么纯migrate,两条路不要混。

3.3 初始化数据与后台账号:没有一条在售商品的商城演示不了任何功能

表建好是骨架,还要灌数据。演示效果好不好,很大程度取决于初始数据像不像真的。我会准备三个分类,每个分类下5个左右商品,价格有梯度、库存一部分为零来演示“缺货”。准备够12个商品是因为列表页要做分页演示,每页通常显示12条,数据太少分页按钮都出不来。

两条初始数据路径,一条是管理后台手工录入,一条是fixture导入。手工录入用createsuperuser建管理员账号:

python manage.py createsuperuser

按提示输入用户名、邮箱、密码。之后登录/admin,在Category和Product页面手动添加。这种方式适合数据量小,但商品图片准备起来麻烦。fixture方式是把数据导出成json,换环境时一次性load进去:

python manage.py dumpdata goods.Category goods.Product --indent 2 > shop_goods.json python manage.py loaddata shop_goods.json

dumpdata导出的文件里带的是模型记录,不包含图片二进制,图片文件本身还要复制到media目录。所以最稳妥的演示方式是:先在本地手工把商品和图片配好,导出json,再把media目录一起打包,换机器后loaddata加复制media两件事都做,商品就齐全了。测试账号也可以dumpdata,但那会带出密码哈希,公开源码里不建议导出用户表,只做演示环境内部用。

4. 核心业务落地:购物车、下单与库存扣减的完整代码路径

数据库有了,管理后台能编辑商品,但用户侧的完整流程——浏览、搜索、加购、下单、扣库存——需要业务代码把它们串起来。这章写的是最简可跑的路径,也是源码里最常被改动的地方。

4.1 商品列表、分页与搜索关键词:一页能拿得出手的ORM查询

商品列表页是商城门面。逻辑是:默认列出所有上架商品,支持关键词搜索,结果按12条一页分页。一个能直接放进views.py的写法:

from django.shortcuts import render from django.core.paginator import Paginator from django.db.models import Q from .models import Product def product_list(request): keyword = request.GET.get('keyword', '').strip() qs = Product.objects.filter(is_on_sale=True) if keyword: qs = qs.filter( Q(name__icontains=keyword) | Q(category__name__icontains=keyword) ) paginator = Paginator(qs, 12) page_obj = paginator.get_page(request.GET.get('page', 1)) return render(request, 'goods/list.html', { 'products': page_obj, 'keyword': keyword, })

filter(is_on_sale=True)只取上架商品,下架商品自然不会出现在用户端。Q对象把两个搜索条件包成OR关系,商品名或分类名任一命中就返还。icontains是大小写不敏感的包含匹配,对应SQL里的LIKE '%keyword%'。Paginator(qs, 12)第一个参数是查询集,第二个是每页条数;get_page从URL的page参数取值,访问/list/?page=2就是第二页。keyword回传模板是为了搜索框里保留上次输入的关键词。

模板里分页控件常见的坑是翻页时丢关键词。分页链接要写成?page={{ products.next_page_number }}&keyword={{ keyword }},不然搜索后再翻第二页,关键词没了,结果变成全部商品。这个细节答辩演示时一翻页就露馅,提前检查。

4.2 购物车用session还是数据库表?两种实现都要会

购物车在毕设里有两派做法。匿名用户、临时用一下,适合放session;登录用户、跨设备保存,适合放shop_cart表。很多源码会两者都实现:未登录时购物车放在session里,登录后把session购物车合并进数据库表。先看加购的session实现:

def add_to_cart(request, product_id): quantity = int(request.POST.get('quantity', 1)) cart = request.session.get('cart', {}) cart[str(product_id)] = cart.get(str(product_id), 0) + quantity request.session['cart'] = cart request.session.modified = True return redirect('cart:detail')

request.session是一个可写的字典对象,key存商品id,value存数量。因为product_id是整数,字典key统一转成字符串,避免类型错乱。request.session.modified = True是告诉Django这个session被改过了必须保存,不加这条,部分情况下会话不会落盘。这个写法不需要登录就能演示加购,答辩现场节奏很快,未登录能加购比先登录再加购少一步。

登录用户的购物车表实现:

from .models import Cart def add_to_cart_db(request, product_id): quantity = int(request.POST.get('quantity', 1)) item, created = Cart.objects.get_or_create( user=request.user, product_id=product_id, defaults={'quantity': quantity}, ) if not created: item.quantity += quantity item.save() return redirect('cart:detail')

get_or_create按user和product两个条件查,没找到就创建,找到就累加。两次并发请求同时加购时,数据库唯一约束可以兜底,但get_or_create本身不是在高并发下绝对安全,毕设场景足够用。

登录合并session购物车到表的代码,放在用户登录视图里:

def login_and_merge(request): # 正常登录逻辑,成功后 cart = request.session.get('cart', {}) for pid, num in cart.items(): item, created = Cart.objects.get_or_create( user=request.user, product_id=int(pid), defaults={'quantity': num}, ) if not created: item.quantity += num item.save() request.session['cart'] = {} return redirect('index')
场景session购物车数据库购物车
未登录用户支持不支持
跨设备同步不支持支持
数据持久性浏览器会话结束清空永久保存
答辩演示流程短、操作快更接近生产系统

合并逻辑把session里的每个商品逐条写入数据库购物车,然后清空session。这个细节答辩老师很爱追问,题目基本是“未登录加购的商品登录后去哪了”,能答出合并这条就算把业务闭环想全了。

4.3 下单、库存扣减与事务边界:防翻车的原子操作

下单是整个系统里最容易翻车的环节,因为涉及多张表:生成订单、写入明细、扣商品库存、加商品销量、清空购物车。任何一步失败,都不能留下半截订单。Django用transaction.atomic包住这一段,任何异常整体回滚:

from django.db import transaction @transaction.atomic def create_order(request): cart_items = list(Cart.objects.filter(user=request.user).select_related('product')) if not cart_items: raise OrderError('购物车为空') total = sum(item.quantity * item.product.price for item in cart_items) order = Order.objects.create( order_no=generate_order_no(request.user.id), user=request.user, total_amount=total, status=1, address=request.user.userprofile.address, ) for item in cart_items: product = Product.objects.select_for_update().get(pk=item.product_id) if product.stock < item.quantity: raise OrderError(f'{product.name} 库存不足') product.stock -= item.quantity product.sales += item.quantity product.save() OrderItem.objects.create( order=order, product=product, product_name=product.name, price=product.price, quantity=item.quantity, subtotal=item.quantity * product.price, ) Cart.objects.filter(user=request.user).delete() return order

这个方法逐行说明。select_related('product')一次性把购物车关联的商品查出来,避免循环里每行触发一次数据库查询,数量少时感觉不明显,商品多了就是几十倍的耗时差。total用Decimal参与sum运算,得到的是Decimal对象,不会像float那样积累误差。先创建Order主表拿到主键,再循环写明细。select_for_update()对商品行加锁,直到事务结束才释放,两人同时抢最后一件商品时,第二个请求会等第一个事务提交后才读到最新库存,防止超卖。库存不足时raise异常,事务整体回滚,这个订单也会撤销,不会留下“有订单没扣库存”的脏数据。

提示:select_for_update 在 MySQL 的 InnoDB 引擎下有效,SQLite 对行锁支持有限,毕设演示事务用 MySQL 才有说服力。

订单号生成函数随手写一个工具方法:

import time import random def generate_order_no(user_id): return f'{time.strftime("%Y%m%d%H%M%S")}{user_id:04d}{random.randint(100, 999)}'

时间戳精确到秒加用户ID加三位随机数,并发演示时重复概率很低。如果老师问你“并发下库存怎么保证不超卖”,能说出select_for_update加事务回滚,这道题就算过了。反过来,如果代码里没有锁、没有事务,下单逻辑各自save,那是典型的扣库存翻车写法,需要重点排查。

5. 编不过、跑不起来、数据对不上:毕业设计最常见的5个坑与排查

源码下了好几份,换了三台电脑,最后卡在同一类报错上的情况我见得太多了。这一章把最常见的坑按现象、原因、解决三步写清楚,按顺序排查,能覆盖八成运行期报错。

5.1 坑一:No module named 'django',pip装了却还是找不到模块

现象:在项目目录执行python manage.py runserver,立刻报ModuleNotFoundError: No module named 'django'。但执行pip list却能看到django已经装好了。

原因:你pip install时用的是全局Python,而运行命令时被虚拟环境隔离了;或者根本没创建虚拟环境,两个Python混用。最常见的情形是Windows上装了多个Python版本,命令行默认的是3.7,而包装进了3.11那一套。

解决:先where python(Windows)或which python(macOS/Linux)看当前Python路径。确认激活了本项目虚拟环境再执行pip install -r requirements.txt。激活后命令行前缀出现(venv),再跑which python路径指向venv目录下的python。装完用pip list确认django在那一个环境里。如果实在分不清,直接把虚拟环境删掉重建:rm -rf venv,然后重新python -m venv venv。

5.2 坑二:MySQL连不上,报2003 Can't connect

现象:执行migrate或者runserver后首次访问数据库时报django.db.utils.OperationalError: (2003, "Can't connect to MySQL server on '127.0.0.1'")。

原因:最直接的是MySQL服务没启动。其次是DATABASES里的HOST、PORT、密码和本机MySQL对不上。还有一种是MySQL从8.0开始默认认证插件是caching_sha2_password,而某些PyMySQL老版本不兼容。

解决:先确认MySQL服务在跑——Windows在服务管理器里看MySQL80是否启动,macOS执行brew services list。命令行用mysql -u root -p -h 127.0.0.1 -P 3306试连,连不上就是服务或端口问题。账号密码在settings.py里改成能登录的那组。认证插件问题则升级PyMySQL到1.1.0以上,并确认OPTIONS里charset是utf8mb4。

5.3 坑三:建表后中文全是乱码

现象:管理后台录入商品名,保存再刷新,页面上全是????或者“锟斤拷”。

原因:MySQL数据库或表的字符集不是utf8mb4,Django写入的UTF-8数据被按latin1解释。建库时默认字符集继承自服务器配置,如果服务器默认是latin1,那库表就跟着错了。

解决:建库时明确指定字符集:

CREATE DATABASE shop_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

已经建错库的,可以改库默认字符集,再转换表:

ALTER DATABASE shop_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ALTER TABLE shop_product CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

改完库表还不够,settings.py连接里OPTIONS的charset=utf8mb4也要配上。两者对齐后,把乱码数据删掉重新录入,旧乱码数据不会自动修复。这个坑在答辩前一天晚上爆出来的概率非常高,提前用SHOW CREATE TABLE shop_product确认一下最省心。

5.4 坑四:商品图片全部裂掉

现象:后台能上传图片,但前台商品图、后台缩略图显示为一个broken image图标。

原因:MEDIA_URL配置了,但开发服务器没有挂载媒体文件路由。Django的runserver默认不处理media目录,需要手工在urls.py挂上。

解决:在项目的urls.py末尾加:

from django.conf import settings from django.conf.urls.static import static if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

这段只在DEBUG=True时生效,生产部署用nginx处理media目录,与Django无关。加了之后重启runserver,图片路径/media/goods/xxx.jpg应该能直接访问。如果还是裂,检查MEDIA_ROOT指向的目录是否存在、图片文件是否真的在,Django不会自动创建目录,目录不存在时上传会报错。

5.5 坑五:目录里有db.sqlite3,启动后却提示连了MySQL

现象:源码压缩包里带着一个db.sqlite3文件,以为改一下就能演示,结果启动后Django报连不上MySQL,或者页面数据为空。

原因:settings.py的DATABASES配的是mysql后端,Django根本不读sqlite3文件。也有相反情况:配置没改、默认连了SQLite,但题目要求是MySQL,交上去的说明里数据库对不上。

解决:先明确这份源码要交给老师的运行环境是什么。以MySQL为准的话,把db.sqlite3当作历史遗留文件忽略,按坑二的步骤把MySQL链路跑通,再migrate建表,导入初始数据。把sqlite当作临时数据源时,可以用Django的databases路由把旧sqlite里的数据导出来,但毕设演示一般不值得花这个时间,直接重新初始化更快。重点是确保交付文档里写清楚:数据库在MySQL里,重建流程是migrate加loaddata。

6. 答辩前的自查清单:三条主链路演示完,这篇毕设就稳了

到答辩前,功能点不再加了,把三条链路跑通就行。按下面这个顺序自测,每条链路走完并截图留档,现场演示就不容易卡壳。

6.1 主链路一:用户侧从注册到支付

开两个浏览器窗口,一个普通用户、一个管理员。用户侧:注册新账号 → 登录 → 搜索关键词 → 商品列表翻页 → 进详情 → 加购 → 购物车页改数量 → 提交订单 → 模拟支付(本地项目一般是把订单状态从1改成2)。每一步验证页面跳转不报错、数据写入正确。

6.2 主链路二:管理侧从商品到订单

管理员登录/admin → 新增一个商品分类 → 在分类下新增商品(上传一张本地图片)→ 到前台确认新商品出现在列表里 → 给用户订单改状态为已发货 → 用户侧看到物流状态变化。这条链路验证的是Django Admin与业务数据的联动,也是老师最容易操作的部分。

6.3 主链路三:数据一致性自查

查三组数据对不对得上:订单总额 = 明细行小计之和;下单前后商品库存减少量与订单购数量一致;商品销量与各订单明细数量累加一致。可以用几条SQL快速核:

SELECT o.id, o.total_amount, SUM(i.subtotal) AS item_sum FROM shop_order o LEFT JOIN shop_order_item i ON o.id = i.order_id GROUP BY o.id, o.total_amount HAVING o.total_amount != item_sum;

查询结果为空说明金额对得上。把这三条链路的操作步骤整理成一页纸的checklist,配合截图放进说明书附录,答辩现场照着走,比临时翻代码稳得多。我自己带毕设时最深的教训是:所有时间花在写代码上,却没花时间把验收路径过一遍,结果现场演示时在“注册后没自动登录”这种小细节上卡了半分钟,而那半分钟足够让老师对整份工作的印象打折扣。先别加新功能,把主链路测通、把坑填平、把讲词顺一遍,希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/4 5:42:25

GitLab + Drone CI 持续集成实践:从Web项目到自动化部署

做DevOps这些年&#xff0c;我越来越认同一句话&#xff1a;持续集成不是炫技&#xff0c;是给团队省心。以前我待过的团队&#xff0c;发布一个Web项目靠的是“人肉部署”&#xff1a;本地build一下&#xff0c;scp到服务器&#xff0c;再手动reload&#xff0c;运气好一次成功…

作者头像 李华
网站建设 2026/10/4 5:41:03

动态张量计算:用字节码虚拟机与实时编译打破静态图困局

过去半年我一直在折腾一个听起来有点偏门的方向&#xff1a;给动态张量计算做一个带字节码虚拟机的运行时&#xff0c;再在这个虚拟机之上叠加实时编译能力。起因非常朴素——业务里一堆长尾模型输入形状跨度极大&#xff0c;从几十个token到上千个token都有&#xff0c;用PyTo…

作者头像 李华
网站建设 2026/10/4 5:40:59

Roo Code本地模型性能优化指南:从硬件到配置全解析

1. 卡顿从哪来&#xff1a;先搞清楚 Roo Code 与本地模型之间的性能链路很多朋友第一次在 Roo Code 里接上本地模型&#xff0c;第一反应都是“这玩意儿也太慢了”&#xff0c;甚至怀疑是不是自己把配置搞错了。其实 Roo Code 本身不慢&#xff0c;本地模型推理也不算离谱&…

作者头像 李华
网站建设 2026/10/4 5:40:32

Codex CLI实战:从代码补全到软件工程智能体接入DeepSeek

我最早接触Codex是在2021年&#xff0c;那时候它还是个藏在论文和API里的代码模型&#xff0c;最出圈的成绩是在HumanEval上刷出了高分&#xff0c;不少开发者拿它当“自动补全加强版”用。这几年再看&#xff0c;大家讨论的Codex已经完全是另一个物种了——它叫Codex CLI&…

作者头像 李华
网站建设 2026/10/4 5:39:06

AI编程工具技能碎片化解法:Skills Manager跨平台桌面中枢实战复盘

过去大半年&#xff0c;我把大量时间花在给 AI 编程工具调教 Agent 行为上。数了数身边同事和团队实际在用的工具&#xff0c;Cursor、Trae、Windsurf、Copilot、Codex、Continue 这些主流 AI 编程工具&#xff0c;再加上各种插件和 CLI 的配置入口&#xff0c;一共牵扯到 54 个…

作者头像 李华