2026/10/11 7:44:17

基于Django的校园二手电子产品交易平台开发实战

基于Django的校园二手电子产品交易平台开发实战 开头最近帮一个学弟折腾了个毕设项目基于Django的校园电子产品交易平台。他毕业论文题目就是这个还附带了一套完整源码拿到手就能跑起来。这项目说白了就是给校内学生提供一个专门交易二手手机、平板、耳机、电脑配件这类电子产品的线上市场。跟闲鱼、转转那种通用平台不太一样它不需要实名认证到身份证级别也不需要物流对接和担保交易核心就是“校内自提、当面验货、线下支付”所以业务逻辑比通用电商平台简化了不少但麻雀虽小五脏俱全。如果你正在准备毕设或者想找一个Django练手项目这个题目非常值得做。它覆盖了Django里最常见的功能模块用户认证、商品发布、图片上传、搜索筛选、订单管理等难度适中既有技术深度又不会卡在某个点上出不来。而且校园场景大家都很熟悉需求合理答辩的时候也容易讲清楚。我花了两天时间把源码整个过了一遍顺便加了一些自己的改造下面把整个项目的拆解思路、核心实现和踩坑记录都写出来希望能帮你少走弯路。1. 项目定位与需求拆解1.1 为什么做校园电子产品交易平台校园里电子产品更新换代快毕业季更是大量闲置设备流转的集中期。苹果的手机、华硕的笔记本这些电子产品二手价值高但高校里活动范围相对集中买卖双方往往就在同一个校区甚至同一栋宿舍楼。通用二手平台的问题在于跨城物流怕摔、怕偷、怕扯皮验机环节又复杂要么寄到平台检测要么当面交易但平台不担责。而校园场景下面对面交易成本极低所以一个“校内直连”的小平台比通用平台更实用。从毕设角度来说这个选题也特别讨巧。它不是单纯模仿淘宝而是针对特定人群做了一个垂直电商业务上有差异点不需要复杂的物流模块支付环节可以简化成线下当面交易核心矛盾集中在“信息展示”和“信任建立”上。这样既保证了技术难度在可控范围内又能在论文里写出“针对校园场景优化”这样的亮点答辩老师一听就觉得这个选题有思考。技术栈选Django而不是Spring Boot或者Go原因有三个。第一Django自带Admin后台可以直接当运营管理界面用省去一大半后台开发时间。第二Django的ORM非常顺手尤其是做关系复杂的查询时比拼SQL快得多。第三Python生态里的图片处理、爬虫、数据分析工具可以直接嫁接过来后期想做扩展很方便。而且国内高校毕设里Python和Django的比例一直不低遇到问题网上资料多不至于卡死。1.2 核心功能模块拆解整个平台按角色划分核心用户是校园内的学生和教职工注册时用学号或工号验证保证“校内”属性。功能大致分成以下几块。用户模块注册、登录、注销个人信息维护头像上传修改密码。登录后可以查看自己发布的商品和参与的订单。商品模块发布二手电子产品编辑商品信息标题、描述、价格、成色、原购买时间上传商品图片支持多图对已发布商品进行下架或删除操作。浏览模块首页展示最新商品支持按分类手机、笔记本、耳机、键盘鼠标等、按价格区间、按发布时间筛选关键还有关键字搜索。收藏模块用户可以把感兴趣的商品加入收藏夹方便后续对比和联系卖家。订单模块买家对商品发起购买申请卖家确认后生成订单记录交易状态待确认、进行中、已完成、已取消交易完成后双方可以互相评价。留言模块商品详情页下方可以留言提问卖家回复构建简单的沟通环境。这套模块拆完以后正好对应Django里的Model、View、Template三件套。每个模块都能在框架里找到很自然的落点不会为了炫技硬塞东西。下面我详细说一下技术选型和架构设计。2. 技术选型与架构设计2.1 Django框架的优势与适用场景Django是个“大而全”的框架内置了ORM、模板引擎、表单处理、Admin后台、认证系统等。对于毕设这种周期短、要求快出成果的项目用Django等于直接用上了官方给你铺好的路。比如用户注册登录如果你用Flask得自己写session、处理密码哈希而Django里直接用django.contrib.auth就能搞定连数据库表都帮你建好了。Django的MTVModel-Template-View架构和传统MVC本质上一样但更强调“约定优于配置”。开发时只要按照规定的方式组织代码就能保持清晰结构。对于校园交易平台这种业务模型之间关系比较明确用户发布商品、商品属于用户、订单关联买家和卖家和商品、收藏是用户和商品的多对多关系完全可以用Django的ORM优雅地表达出来。还有一个关键点Django自带Admin后台。毕设答辩时老师们总喜欢看“管理端”你直接用Admin注册几个模型就能实时增删改查所有数据不用额外写后台页面。这节省的精力可以用来打磨用户端界面和交互。2.2 数据模型设计思路设计数据库表是整个项目的基石。我重新整理了一下模型关系画出来的话大概是这样的核心表是User用户和Product商品User和Product是一对多关系一个用户发布多个商品Order订单关联两个用户买家、卖家和一个商品Favorite收藏是用户和商品的多对多关系表Comment留言关联一个用户和一个商品。以Product表为例重要的字段有title商品标题CharField最长100个字符。description商品描述TextField可以写状态、使用年限、购买渠道等。price价格DecimalField精度到分防止float运算误差。category分类CharField用choices定义枚举比如手机、笔记本、平板、配件。condition成色状态用choices定义比如全新、几乎全新、轻微使用痕迹、明显使用痕迹。image图片ImageField上传后自动保存到media目录。seller外键关联User指向卖家。status商品状态比如在售、已下架、已卖出。created_at发布时间自动记录。这里有几个设计细节值得注意。价格字段必须用DecimalField而不是FloatField因为float在二进制表示下会丢失精度虽然平时显示不出来但涉及金额相关的统计时容易出bug。分类用choices而不是单独建一张分类表因为校园交易平台商品种类就那几类用常量枚举实现更简单查询时也不用关联表性能更好。成色字段同理。订单状态我用了一个整数字段加choices定义了待卖家确认、交易中、交易完成、已取消四种状态。为什么不直接改商品状态来标记卖没卖出去因为订单状态可能比商品状态多几个维度比如“买家已付款但卖家未发货”这种中间态商品状态只需要“在售”和“已卖出”两种就够了所以分开维护更合理。但要配合好商品卖出后要同步把商品状态置为已卖出不然别人还能看到这件商品。2.3 前后端交互与API设计这套项目用的是Django模板渲染不是前后端分离。对于毕设来说前后端分离意味着要额外搭建前端工程、处理跨域、写API文档工作量翻倍而且答辩时不好解释“前端框架和Django之间是怎么通信的”。直接用Django模板配合Bootstrap做样式一套搞定整个项目跑起来只有一个服务适合快速出成品。不过模板渲染也要讲究规范。视图函数里尽量只处理业务逻辑渲染模板时才组装数据不要一股脑查一堆数据塞给模板要用到啥查啥。列表页和详情页分开做列表页用分页详情页单独一个URL对应一个视图这样代码结构清楚出问题也好排查。API设计上虽然没有做RESTful接口但URL设计还是要有层级关系。比如商品列表是/products/详情是/products/int:id/发布是/products/create/订单是/orders/这样即使以后想改成前后端分离也能快速把这套路径映射成API。我在源码里看到原作者也是这么做的直接复用没问题。3. 核心功能实现与实操解析3.1 用户认证与权限管理用户模块直接继承了Django自带的User模型没有做扩展。如果要存学号、手机号这些字段可以用Profile模型通过外键关联User这样改动最小。源码里是直接在User上加了student_id字段用OneToOneField搞了个StudentProfile也行但后期维护时有点绕我建议直接用Profile模式清晰一点。登录和注册实现起来不复杂。注册页面用Django内置的UserCreationForm改造一下加上邮箱和学号字段校验学号是否合法比如是否以入学年份开头注册成功后手动登录。登录页面直接用LoginView配置模板路径就行。权限管理方面发布商品、访问订单列表这些操作必须要求用户登录用login_required装饰器几行代码搞定。有一个地方特别容易踩坑Django的认证系统默认用的用户名登录但校园平台大家更习惯用学号登录。我的做法是自定义一个认证后端验证学号和密码而不是用默认的ModelBackend。这样既保留了Django的用户体系又符合校园使用习惯。源码里用的是默认方式我改了一版代码量不多但体验好很多。from django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model User get_user_model() class StudentIDBackend(ModelBackend): def authenticate(self, request, usernameNone, passwordNone, **kwargs): try: user User.objects.get(student_idusername) except User.DoesNotExist: return None if user.check_password(password): return user return None然后在settings.py里配置AUTHENTICATION_BACKENDS改成这个类这样登录表单里填学号就能登录很方便。3.2 商品发布与图片上传商品发布页面要用Django Form来做因为Form自带校验和错误提示功能。我创建了一个ProductForm里面用ModelForm直接映射Product模型这样能省掉大量重复代码。图片上传这块特别注意ImageField只在Form里写了一个但实际业务上需要支持多图上传。我的方案是用ImageField加JavaScript动态添加input标签同时用一个隐藏字段记录图片顺序和数量。也可以直接用第三方库django-multiupload但毕设里加第三方库会增加复杂度我建议还是自己写一个简单的多图上传。具体实现方法在表单里用multiple属性视图函数里通过request.FILES.getlist(images)获取文件列表然后循环保存。图片保存路径可以在MEDIA_ROOT下按用户和商品ID建日历目录避免文件名冲突。文件类型和大小也必须在后端校验前端只是方便用户后端才是安全底线。图片处理方面我没有用Pillow做压缩因为用户的手机相机拍的照片动辄几MB直接存服务器太占空间。我写了一个简单的压缩函数用Pillow把图片统一缩到最大1200像素宽质量设为85实测体积能减少70%左右页面加载速度明显变快。这个优化点可以在答辩时主动提容易加分。from PIL import Image def compress_image(uploaded_file): img Image.open(uploaded_file) img.thumbnail((1200, 1200)) img.save(uploaded_file.name, optimizeTrue, quality85) return uploaded_file3.3 搜索与筛选功能搜索和筛选是交易平台的核心体验。我用了Django ORM的filter链式查询配合多个查询参数实现。商品列表页的URL后面支持?q关键词category手机price_min100price_max1000这种格式。视图里先取出所有在售商品然后依次根据查询参数filter。products Product.objects.filter(statuson_sale) if q: products products.filter(title__icontainsq) | products.filter(description__icontainsq) if category: products products.filter(categorycategory) if price_min: products products.filter(price__gteprice_min) if price_max: products products.filter(price__lteprice_max)这里有个细节用|做OR查询时Django的QuerySet不会自动去重。如果商品标题和描述里都有同一个关键词就会返回两条记录结果出现重复商品。解决办法是在|查询之后加一个.distinct()保证每个商品只出现一次。排序逻辑我用的是created_at字段按时间倒序排最新发布的放在最前面。还可以通过order_by参数支持按价格升序降序排序这个在模板里放几个链接就行。分页用Django内置的Paginator每页12个商品。模板里渲染分页页码时要注意如果有多组查询参数分页链接上必须携带之前的查询条件不然点第二页时搜索结果就没了。我写了个小函数把request.GET参数拼到分页链接里这也是个容易漏的细节。3.4 订单管理与状态流转订单这块是整个平台逻辑最复杂的部分。一个订单涉及到买家、卖家和商品三个主体状态有四种待确认、交易中、已完成、已取消。我在Order模型里定义了status字段用choices限制合法值。同时还要定义状态流转的规则比如只有待确认状态才能变为交易中交易中才能变为已完成等。光在模型里定义状态还不够我建议把这些规则写成模型方法比如confirm()方法、cancel()方法。这样避免在视图里散落一堆if-else逻辑容易失控。比如订单创建后卖家在订单详情页点击“确认交易”时视图调用order.confirm()方法方法内部检查当前状态是不是待确认如果是才更新状态并保存。class Order(models.Model): # 其他字段... def confirm(self): if self.status ! pending: raise ValidationError(当前状态无法确认交易) self.status trading self.save() def cancel(self): if self.status not in [pending, trading]: raise ValidationError(当前状态无法取消订单) self.status cancelled self.save()交易闭环后商品状态也要同步。确认订单时把商品状态改为“已卖出”取消时改回“在售”。这里我用Django的信号signal来做联动每次保存订单状态变化时自动更新对应的商品状态。好处是哪怕在别的地方改了订单状态商品状态也不会漏更新。不过信号写得不好容易产生循环调用需要在信号函数里小心判断。评价功能我放在订单完成之后买家对卖家评分和留言评分可以是一个1-5星的定义。这个功能直接复用了Comment模型加了一个rating字段没额外建表挺省事。4. 部署与源码使用指南4.1 环境配置与依赖安装源码拿到手第一步是配置Python环境。建议用Python 3.10或3.11对应的Django版本用3.2 LTS稳定且资料多。先创建虚拟环境再安装依赖。python -m venv venv source venv/bin/activate # Windows是 venv\Scripts\activate pip install django3.2 pillow django-crispy-forms源码里如果带了requirements.txt直接pip install -r requirements.txt。但注意有些毕设源码的requirements版本可能很老安装时会有兼容性问题建议根据当前环境调整版本号比如把Django降到3.2或者升级到4.2都能跑通。我遇到一个坑是Pillow版本和Python版本不匹配导致图片上传的字段报了Could not import PIL.Image。解决办法很简单卸载重装最新Pillowpip uninstall pillow然后pip install pillow。还有crispy-forms这个库新版用法已经变了如果模板里报错可以暂时不用它直接用{{ form.as_p }}输出表单也能搞定。4.2 数据库迁移与初始化Django项目里数据库配置默认是SQLite毕设完全够用不用特意换MySQL。SQLite对于单机使用轻轻松松而且免安装文件型数据库移植也方便。在settings.py里确认一下数据库配置然后执行迁移命令。python manage.py makemigrations python manage.py migrate执行完迁移后数据库表就建好了。接下来创建一个超级管理员python manage.py createsuperuser如果你需要测试数据源码里经常会有fixtures目录里面是JSON格式的初始数据可以用loaddata命令加载python manage.py loaddata initial_data.json没有测试数据也不影响你可以先去Admin后台手动添加几个商品和用户或者直接在Python shell里批量生成python manage.py shellfrom django.contrib.auth.models import User from products.models import Product user User.objects.create_user(usernametest, passwordtest123) Product.objects.create(titleiPhone 12, price2500, selleruser)4.3 运行与测试配置好环境后运行开发服务器python manage.py runserver浏览器打开http://127.0.0.1:8000/就能看到首页了。源码里如果写了urls.py可以直接访问相应路径。另外记得把media目录的访问加上在urls.py里加一行from django.conf import settings from django.conf.urls.static import static urlpatterns static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)不配这行上传的图片没法显示。测试的时候重点测几块逻辑注册、登录、发布商品、搜索筛选、下单、确认交易。核心流程能跑通毕设演示就没问题了。如果你想写单元测试重点测Order的状态流转和商品搜索的过滤结果这两个是最容易出逻辑错误的地方。4.4 源码结构与扩展建议附带的源码结构一看就是标准Django项目布局。根目录下是manage.py项目配置在一个和项目同名的文件夹里应用有users、products、orders等。找到核心应用直接从models.py、views.py、urls.py、templates入手就行。拿到源码后我建议你先做三件事第一全局搜索一下DEBUG和SECRET_KEY确认没有把这些传到公共环境毕设源码经常会泄漏这两个东西。第二把项目里所有的绝对路径改掉很多源码里写死了一些/home/xxx/之类的路径运行时会报错。第三用pip freeze requirements.txt重新生成依赖清单后续部署到服务器或者给指导老师演示时不会缺包。如果你觉得框架基础功能做完还不够“高级”可以加一些延伸功能用django-channels实现站内信通知卖家收到新订单时浏览器推送消息。接入短信或邮箱验证码实现手机号注册。用Redis做缓存热门商品详情页缓存起来减轻数据库压力。加一个统计报表模块用Django的aggregate函数统计每月成交量、热销品类。这几个扩展方向难度梯度合理挑一个做就能让项目比别人多一个亮点而且都能在论文里找到对应的章节。5. 常见问题与排查技巧实录5.1 Django版本兼容性问题毕设源码的Django版本往往固定在一个旧版本上比如Django 2.2或者3.0。但新装的Python 3.11可能不支持那么老的版本。最容易碰到的报错是AttributeError: str object has no attribute decode。这通常是因为代码里用了Python2风格的字符串处理而新版本Django已经移除了对str.decode的支持。解决办法就是要么升级Django到当前兼容版本要么把出错的代码行改成bytes类型转换。另一个兼容性问题出现在URL配置上。老版本Django用正则表达式url(r^products/$)新版本推荐用re_path或path。如果源码里的urls.py全是url()函数直接跑会报ImportError。我的处理方法是用path()重写几个关键URL其他不常用的先注释掉确保核心功能能跑起来就行。遇到版本问题不要慌先去报错信息里看第一个traceback基本就是问题所在。再配合搜索引擎查一下明确的关键词组合比如“Django 3.2 url() AttributeError”一般两分钟就能找到答案。5.2 静态文件与媒体文件部署问题开发模式下Django会自动帮你处理静态文件的请求但一旦放到生产环境或者交给老师演示静态文件如果配不好就会全乱。常见的现象是页面能打开但没有任何CSS样式图片也全部裂掉。原因很简单FileSystemFinder找不到静态文件目录。检查一下settings.py里有没有配置STATIC_ROOT和STATIC_URL。如果DEBUG是True模板里需要加{% load static %}CSS链接写成{% static css/style.css %}。媒体文件同理要确保MEDIA_URL和MEDIA_ROOT有值并且在urls.py里加静态服务于MEDIA_ROOT。如果还是不行给静态文件放一个明确的独立目录比如项目根目录下建static/文件夹然后在settings里设置STATICFILES_DIRS [BASE_DIR / static]。5.3 并发与性能优化毕设的并发量通常不大但不代表你可以随便写代码。很多源码在商品列表页直接Product.objects.all()一旦数据超过几百条页面就卡得像PPT。我的建议是加上select_related和prefetch_related因为列表页需要同时显示卖家信息和图片用select_related(seller)能减少大量数据库查询。products Product.objects.filter(statuson_sale).select_related(seller)另一个性能优化点是分页和懒加载。图片不要一次加载全部用Django的{{ forloop.counter }}配合图片文件名的递增或者直接用JavaScript做滚动懒加载也能明显提升体验。缓存方面Django自带了cache模块可以把热门商品列表缓存10分钟这样重复点击时直接命中缓存数据库压力小很多。5.4 安全防护要点毕设源码最容易被人忽视的就是安全问题但答辩老师可能恰好揪住这一点。比如XSS攻击如果用户发布的商品描述里带JavaScript代码模板渲染时如果用了|safe过滤器代码就会被执行。解决办法是不要在模板里对用户输入的内容加|safeDjango默认会自动转义HTML只要你不去主动关掉它。CSRF防护方面Django的模板表单里默认会生成csrf_token但有些源码为了省事会在Ajax请求里忽略它这会导致提交失败或安全隐患。我的做法是所有POST请求都通过Django的CsrfViewMiddleware并且在模板里始终带上{% csrf_token %}。接口方面登录接口必须加限流防止暴力破解可以在视图函数里加一个简单的IP访问次数计数。还有一个细节是SQL注入。Django的ORM已经帮你防了大部分但如果你用了raw()写原生SQL就必须注意参数化。我建议整个项目禁止使用raw()全部走ORM这样从根源上杜绝注入风险。密码存储方面Django默认的PBKDF2算法已经够强千万别为了省事改回MD5或SHA1。结尾这套项目做下来我自己最大的体会是毕设源码拿到手不能直接用一定要自己从头走一遍环境配置流程把每个报错都解决一遍才能真正理解它的架构和逻辑。很多人图省事直接clone下来运行结果卡在环境上然后四处找答案反而浪费时间。实际上只要胆子大一点把报错信息贴到搜索引擎里绝大多数问题都能解决。而且修改源码过程中你会发现Django的坑基本都是自己逻辑不清造成的框架本身真的非常稳定。如果你准备拿这个题目做毕设建议你花一晚上把需求分析和数据模型设计吃透第二天动手改代码第三天写论文节奏刚刚好。最后再分享一个小技巧答辩演示前一定提前把数据库清干净导入两三个看起来很真实的二手商品数据比如“iPhone SE2 95新”“AirPods Pro 二代 一年使用痕迹”这种演示效果比空白页面强一百倍。