ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Django+Vue+DeepSeek:电商平台的智能全栈开发实战

Django+Vue+DeepSeek:电商平台的智能全栈开发实战 又到一年毕业设计季打开选题列表在线购物平台这种经典电商题目几乎年年都在。题目虽然老但做出来的水平差距能大到离谱大部分人交的是CRUD换皮的增删改查答辩时讲不出几个技术亮点少数人把数据分析、大模型Agent这些新东西融进老题目一下子就成了有技术含量的项目。这篇博文要拆解的就是后者——一个基于Python Django框架做后端、Vue做前端、内置数据可视化大屏、接了DeepSeek大模型Agent的在线购物平台从架构选型到数据建模再到可视化和Agent集成的完整思路。无论你是正在选毕业设计题目还是想给简历加一个全栈AI项目这篇文章都值得花几分钟看完我尽量把能直接复用的做法和踩坑经验都写出来。1. 为什么这个项目值得做技术栈选择的真实逻辑先说结论这个项目把电商系统这个老题目硬生生做出了一层新意。核心思路是——电商做底盘数据分析做亮点大模型Agent做加分项。题目还是那个题目但完成度已经不是一个级别。1.1 后端选Django而不选Spring Boot理由不只是好上手很多同学在选题时会纠结后端框架。Spring Boot在国内招聘市场占有率确实高但放在毕业设计这个场景里Django的优势是碾压级的。第一开发效率。Django自带Admin后台、ORM、Migration机制、认证系统一个电商平台里用户的登录注册、权限管理、后台管理等这些又麻烦又不值钱的模块Django几乎都是开箱即用。我算过一笔账同样功能的电商后端用Django能比Spring Boot至少省出两周时间。这两周时间拿去干什么不好深入搞搞数据分析、调调大模型Agent它不香吗第二Python语言本身的生态。电商平台要做的数据分析、可视化、大模型接入全都是Python的主场。Django写后端数据分析也用Python大模型SDK也是Python优先支持整个项目保持一种语言学习和联调成本都低。Spring Boot那套Java生态当然也能做但你要同时维护Java后端和Python分析脚本复杂度翻倍。第三答辩时为什么选型这个问题好回答。你能说出Django的ORM天然适配Python数据分析链路实现后端和大模型Agent无缝协作这种话比干巴巴说Spring Boot生态好要有说服力得多。1.2 前端选Vue的另一个隐性理由Vue不是前端技术里唯一的选择但在毕业设计这个场景里是最合理的。Vue 3 Vite的组合启动快、开发体验好而且是国内企业用的最多的前端框架之一很多公司前端岗就是Vue栈写进简历有直接价值。更实际的好处是Vue生态里有一套非常成熟的电商中后台组件库——Element Plus。表格、表单、弹窗、分页全都现成不用自己去手写样式。做可视化管理后台的时候Element Plus配合ECharts一套管理界面两天就能搭出来。如果是React虽然也有Ant Design但整体学习曲线比Vue陡一些对时间紧的毕业设计来说这是实打实的成本。1.3 大模型选DeepSeek而不是OpenAI钱和时间都是理由项目标题里点名了deepseek这个选择其实非常务实。OpenAI的API在国内访问不稳定而且结算麻烦对预算有限的毕业设计来说不友好。DeepSeek的API兼容OpenAI的接口格式代码里只需要改base_url和api_key几乎零成本切换。更重要的是DeepSeek的上下文长度和价格对毕设这种级别的应用完全够用。你要在项目里跑一个Agent无非就是让模型做意图识别、调用工具、生成推荐文案DeepSeek都能完成得很好。而且DeepSeek是国产模型答辩时被问到为什么选它你可以理直气壮说国内模型、合规稳定、接口兼容OpenAI这个答案无懈可击。1.4 整体架构分层一张图说清系统怎么拼这个项目的架构可以拆成四层前端展示层Vue 3 Vite Element Plus ECharts负责用户端购物页面、管理端数据大屏。后端服务层Django Django REST Framework提供RESTful API处理业务逻辑、权限认证、数据校验。数据存储层MySQL存业务数据Redis做缓存和Session解决可视化大屏和大模型调用时的热数据访问。智能服务层DeepSeek大模型API Agent工具调用负责智能客服、商品推荐、自然语言查数据等能力。层和层之间通过HTTP/JSON通信职责清晰。所有跟大模型相关的逻辑单独抽一层不跟业务代码强耦合——这个设计在答辩时加分因为体现了一种模块化、可扩展的工程思维。2. 电商核心业务的数据建模从商品到订单再到采购可视化做得再炫、Agent接入得再花哨电商平台的根基还是数据模型。这个部分我详细拆一下核心的表结构设计以及为什么这么设计。2.1 核心模型体系用户、商品、订单、采购四板斧电商平台的数据模型绕不开这四个核心实体用户User、商品Product、订单Order、以及标题里特别提到的采购Purchase。很多人做电商系统时会把采购模块漏掉但在线购物平台既然包括采购那就不能只是C端卖货还要有B端采购补货的逻辑。Django的模型定义大致如下from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): 扩展Django自带的User模型 phone models.CharField(max_length11, blankTrue, nullTrue) avatar models.ImageField(upload_toavatars/, blankTrue, nullTrue) is_supplier models.BooleanField(defaultFalse) # 是否供应商 class Category(models.Model): 商品分类 name models.CharField(max_length64, uniqueTrue) parent models.ForeignKey(self, nullTrue, blankTrue, on_deletemodels.CASCADE) sort models.IntegerField(default0) class Product(models.Model): 商品 name models.CharField(max_length128) category models.ForeignKey(Category, on_deletemodels.PROTECT) price models.DecimalField(max_digits10, decimal_places2) stock models.IntegerField(default0) sales_count models.IntegerField(default0) description models.TextField(blankTrue) cover models.ImageField(upload_toproducts/, blankTrue, nullTrue) status models.IntegerField(choices( (0, 下架), (1, 上架), ), default1) created_at models.DateTimeField(auto_now_addTrue)这里有几个细节值得注意。价格字段用DecimalField而不是FloatField因为浮点数在计算机里本身就是近似值金额算错一毛钱都是问题。分类表用自关联ForeignKey(self)实现两级分类比搞一个扁平的分类字段灵活得多。商品状态的choices参数配合Django表单和序列化器能自动转换成可读的枚举值这个细节答辩时随口说出来老师就知道你不是照抄的代码。订单和订单明细是典型的主表明细表设计核心逻辑在于订单明细为什么要单独建表class Order(models.Model): 订单主表 order_no models.CharField(max_length32, uniqueTrue) user models.ForeignKey(User, on_deletemodels.PROTECT, related_nameorders) total_amount models.DecimalField(max_digits12, decimal_places2) status models.IntegerField(choices( (0, 待支付), (1, 已支付), (2, 已发货), (3, 已完成), (4, 已取消), ), default0) address models.CharField(max_length255) created_at models.DateTimeField(auto_now_addTrue) class OrderItem(models.Model): 订单明细 order models.ForeignKey(Order, on_deletemodels.CASCADE, related_nameitems) product models.ForeignKey(Product, on_deletemodels.PROTECT) product_name models.CharField(max_length128) # 快照 product_price models.DecimalField(max_digits10, decimal_places2) # 快照 quantity models.IntegerField()product_name和product_price这两个字段看起来冗余实际是刻意设计的快照。为什么因为商品名称和价格未来可能改但订单一旦生成当时买的什么、多少钱必须按历史数据保留。如果订单明细通过外键去实时关联商品表商品改价后历史订单的对账就全乱了。这个设计在简历上写一笔订单明细快照机制懂行的人一看就知道你考虑过真实业务。采购模块跟订单模块结构相似但语义不同订单是C端用户向平台买采购是平台向供应商买。设计时单独建Purchase和PurchaseItem与订单分开管理避免业务混乱。采购单的核心价值在于电商平台卖货过程中库存会持续消耗采购模块跟库存变更联动才能形成销售-补货的业务闭环。2.2 权限体系设计普通用户、管理员、供应商三种角色Django自带User模型已经处理了is_staff、is_superuser这类权限标记但电商系统还需要更细的粒度。我用的是比较朴素的三角色体系普通用户能浏览商品、加购物车、下单、支付模拟、查看个人订单。管理员能管理商品上下架、处理订单发货、看数据大屏。供应商能维护自己供应的商品库存、查看采购单。实现方式就是抽一个user_type字段或在User上挂is_supplier布尔值配合Django REST Framework的权限类做接口级控制。比如供应商接口就必须校验request.user.is_supplier否则返回403。毕业设计做到这个程度已经比绝大多数只做了用户和管理员的电商系统深一层了。2.3 数据库层面的优化索引、外键与查询性能数据模型定下来之后别忘了加索引。商品表的category_id、订单表的status和created_at都建议加索引。因为可视化大屏要按时间聚合销售额按分类统计销量没有索引数据量稍微上来一些接口就会明显变慢。Django里加索引很简单class Order(models.Model): ... created_at models.DateTimeField(auto_now_addTrue, db_indexTrue) status models.IntegerField(choices..., default0, db_indexTrue)外键删除策略这里也提一句。商品被订单引用后用PROTECT防止误删有历史订单的商品订单删除时用CASCADE连带把订单明细删掉避免出现订单主表没了明细表还留着的孤儿数据。这种细节很琐碎但恰好体现了一个人的工程意识。3. 数据分析与可视化给平台装上经营仪表盘如果说订单流水是电商系统的日常操作那数据分析可视化模块就是整个项目的高光时刻。这个模块做得好不好直接决定答辩现场能不能让评委眼前一亮。3.1 可视化的目标不是画图而是辅助经营决策很多人做可视化只是把数据堆到图表上销售额、订单数、用户数各画一个图就算完事。这样做的本质是为了可视化而可视化答辩时老师说一句你这个图能说明什么经营问题就直接哑火。正确的思路是倒过来想管理者看到这些图表之后能做什么决策围绕这个逻辑我把可视化模块分成四块销售趋势分析看销售额随时间变化判断增长还是下滑辅助补货决策。品类销售结构分析看哪些品类是主力哪些品类滞销辅助选品决策。热销商品排行识别爆款商品决定是否加大库存采购。用户活跃分析看新增用户数、订单量变化评估平台运营效果。每一块图表背后都有一个所以呢——看到趋势之后下一步该做什么。答辩的时候能讲出这层逻辑比贴十几张ECharts截图有价值得多。3.2 后端聚合查询Django ORM一行代码搞定统计可视化图表的数据来源是后端的聚合查询接口。Django ORM里最常用的就是annotate配合Sum、Count再加上TruncMonth做时间分组。以月度销售额趋势为例from django.db.models import Sum from django.db.models.functions import TruncMonth def sales_trend(request): rows (Order.objects .filter(status1) # 已支付订单才算销售额 .annotate(monthTruncMonth(created_at)) .values(month) .annotate(totalSum(total_amount)) .order_by(month)) return JsonResponse({data: list(rows)})这段代码的思路是先按月份截断时间字段再按月份分组求和。TruncMonth是Django处理时间归类的神器能自动把2024-06-15 14:30:00归到2024-06-01。回到前端ECharts只需要拿到month和total两组数据一条折线就出来了。品类占比分析也能一行搞定from django.db.models import Count def category_ratio(request): rows (Product.objects .values(category__name) .annotate(countCount(id)) .order_by(-count)) return JsonResponse({data: list(rows)})注意category__name的双下划线写法这是Django ORM跨表查询的固定语法通过Product直接关联到Category的字段不需要手动写JOIN。3.3 前端大屏的搭建思路与性能优化拿到后端接口的数据之后前端用ECharts渲染。ECharts跟Vue的整合方式有两种一种是用vue-echarts封装组件另一种是直接在mounted生命周期里初始化echarts实例。我建议用前者代码更干净组件卸载时还能自动销毁实例避免内存泄漏。大屏页面的布局建议用栅格系统比如把屏幕分成12列销售趋势图占6列品类占比图占6列热销排行和用户活跃各占4列。用CSS Grid或者Element Plus的el-row/el-col都能实现。注意大屏的适配问题固定宽度写100%而不是像素值字体单位用rem或者配合vw这样在不同分辨率的屏幕上不会错位。性能方面大屏页面打开时会同时请求多个统计接口如果数据量大接口耗时可能上到三到五秒。两个优化手段很实用第一个是后端加缓存用Redis把统计结果缓存60秒大屏要求准实时而不是精确实时60秒的延迟完全足够第二个是前端用异步并发请求一次性发起Promise.all把四个图表的数据全部拿到再渲染避免串行请求叠加耗时。还有一个被很多人忽略的坑ECharts的折线图X轴如果数据点太多比如按天统计365天X轴标签会全部挤在一起。解决办法是axisLabel里设置interval: 0配合rotate: 45让标签旋转45度显示或者后端做降采样按月统计而不是按天统计。毕设的数据量不大按月统计通常就够了。4. DeepSeek大模型Agent接入实践让平台学会自动干活这部分是整个项目最大的亮点。Agent不是挂一个ChatBot对话框那么轻飘而是要让大模型能调用系统内的真实功能——查订单、查库存、生成采购建议——这才是Agent和聊天机器人的本质区别。4.1 明确Agent的应用场景它到底能替用户干什么在动手写代码前先想清楚Agent要承担哪些职责。我规划的三个场景智能客服用户问我的订单什么时候发货Agent自动识别订单号调用订单查询工具返回真实状态。发卡类数据查询管理员问这个月销售额多少Agent调用销售统计工具返回真实数字。采购建议供应商问哪些商品需要补货Agent调用库存查询工具结合安全库存线给出建议。这几个场景有一个共同点——Agent必须动真格的不能编造数据。大模型不知道你数据库里的实际库存和订单它必须通过你定义的工具函数去查询把真实结果拿回来再组织语言回复用户。4.2 DeepSeek调用方式的实操细节DeepSeek的API完全兼容OpenAI的格式所以代码可以直接用openai这个Python包只需要改base_url。示例代码如下from openai import OpenAI client OpenAI( api_keyyour-deepseek-api-key, base_urlhttps://api.deepseek.com ) resp client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: 你是智能购物助手能查询订单、库存回答用户问题。}, {role: user, content: 帮我查一下订单202406150001的状态} ], tools[ { type: function, function: { name: query_order_status, description: 根据订单号查询订单当前状态, parameters: { type: object, properties: { order_no: {type: string, description: 订单编号} }, required: [order_no] } } } ], tool_choiceauto )关键点在于tools参数它告诉大模型你手上有哪些工具可以用。当用户问题命中某个工具的能力范围时模型不直接硬编答案而是返回一个tool_calls请求里面包含了它想调用的函数名和参数。这时候后端需要写一个分发函数def execute_tool(tool_name, params): if tool_name query_order_status: order Order.objects.get(order_noparams[order_no]) return {status: order.get_status_display(), ...} if tool_name check_stock: ... return {error: unknown tool} # 拿到tool_call后执行工具再把结果回传给模型 tool_result execute_tool(tool_name, tmp_args) messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(tool_result, ensure_asciiFalse) }) resp client.chat.completions.create( modeldeepseek-chat, messagesmessages, toolsTOOL_DEFINITIONS, ) # 最终模型的回复就是给用户的自然语言答案这段模型请求工具→执行工具→回传结果→模型组织语言的循环就是Agent最核心的ReAct模式。说白了Agent就是一个会查工具的大模型它的回答有数据支撑不再是凭空生成。4.3 Agent与Django的工程整合实践把Agent接进Django项目时有几个工程层面的点必须处理好。API Key不能写死在代码里更不能提交到Git仓库。最稳妥的做法是存到环境变量或Django的settings.py里混用本地配置文件.env文件配合python-dotenv读取。答辩时讲到这里安全意识是一个加分项。调用DeepSeek的接口应该封装成一个独立的service比如services/agent_service.py不要在视图函数里直接写请求代码。因为Agent调用链路比较长视图接收用户消息→组装messages→调大模型→执行工具→再调大模型→返回结果。如果你把这段逻辑堆在views.py里一是代码会非常长二是以后想换模型或者加工具得改一堆地方。抽成service之后视图里两行代码搞定def agent_chat(request): msg request.data.get(message) reply agent_service.chat(msg, request.user) return Response({reply: reply})4.4 踩坑记录模型回复不稳定与输出校验大模型Agent有个很现实的问题它不是每次都能正确生成参数。比如用户说帮我看看最近订单模型提取订单号的时候可能提取出最近两个字当参数这显然是错的。我在实测中就遇到过这样的情况工具参数校验不通过整个Agent链路就断了。解决办法是在工具执行函数里做参数校验查不到订单号就抛出业务错误并把错误信息回传给模型让它重新生成参数。这个环节叫做带反馈的重试。另外要给Agent的最终回复加一个兜底机制如果模型生成的内容明显不合理比如返回空字符串、或者说我不确定前端要有一个默认的友好文案。别小看这些细节答辩演示的时候遇到一次模型却生成了一堆乱码的情况整个项目的印象分就没了。5. 联调、部署与答辩别让细节拖垮你的项目代码写完了做出来一堆功能最后能不能顺利跑通、能不能在答辩现场撑住场子其实取决于一些看起来不起眼的配置和准备工作。5.1 前后端联调必踩的跨域坑Vue前端跑在http://localhost:5173Django后端跑在http://localhost:8000端口不一样直接通信就会被浏览器的同源策略拦下来。你会在浏览器控制台看到经典的CORS报错。解决方式是用django-cors-headers在settings里配置允许的来源INSTALLED_APPS [ ... corsheaders, ] MIDDLEWARE [ corsheaders.middleware.CorsMiddleware, ... ] CORS_ALLOWED_ORIGINS [ http://localhost:5173, http://127.0.0.1:5173, ]有个细节是CorsMiddleware必须放在CommonMiddleware前面不然顺序错了CORS头还是加不上。这一条我当年折腾了快一个小时才明白属于典型的花时间最多的环节往往是最没技术含量的环节。5.2 图片上传与静态文件的经典迷局电商系统必然有商品图片。Django开发环境处理上传文件需要两处配置MEDIA_URL和MEDIA_ROOT并且在主路由里把media目录挂出来from django.conf import settings from django.conf.urls.static import static urlpatterns [ ... ] static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)上面这行代码必须有否则商品图片在开发环境里访问不到页面上全是裂图。毕业设计一般不需要真的做对象存储本地存储加一个处理就够但你要能在答辩时说出生产环境应该迁移到OSS/COS本地存储只用于开发这句话显得你考虑过工程问题。5.3 答辩前的预演准备把讲项目变成一个故事答辩的逻辑跟写代码的逻辑不一样。写代码是从底层往上构造答辩是要从用户场景出发把系统为什么存在、怎么工作、有什么亮点串成一个故事。我会这样组织讲述主线开场讲清楚面向的用户和管理者——普通用户能购物管理员能管店供应商能补货。然后说技术架构如何支撑这些角色——Django的权限体系、三种角色的接口隔离。接着重点讲可视化模块和大模型Agent——这是你跟其他做电商题目的人拉开差距的地方。可视化不是画图是经营决策Agent不是聊天是真的能调用系统工具解决用户问题。最后讲一个你在开发中解决的真实问题——比如跨域、图片上传、或者Agent工具参数校验这个故事要让评委觉得你有独立解决问题的能力。5.4 老师大概率会问的问题提前准备你的Agent和普通ChatBot有什么区别答Agent能调用系统内真实的工具函数返回的是数据库里的真实数据而ChatBot只是生成文本。举一个查订单状态的例子把工具调用链路讲清楚。可视化数据是实时的吗答准实时后端做了60秒缓存对经营决策场景足够同时避免了大屏刷新对数据库造成压力。系统能支撑多大的并发答诚实一点直接说当前架构在低并发场景几十到几百量级没问题然后讲如果要抗高并发可以加Nginx做负载均衡、上消息队列、做读写分离这些扩展思路能说出来就是加分项。采购和订单的关系是什么答订单是C端卖货采购是B端补货采购模块联动库存库存联动订单可售数量是整个电商循环的完整闭环。6. 实测中的几个隐藏坑与补救措施最后说几个我在实际开发过程中被卡住过的地方这些坑不一定会出现在任何教程里但遇到了是真浪费时间。6.1 Django的数据库迁移冲突多人协作或频繁修改模型时makemigrations和migrate容易出问题最常见的是字段冲突你改了某个字段的类型但之前生成的迁移文件里还是旧类型。我的经验是开发初期模型还没定型时干脆删掉migrations目录里的迁移文件保留__init__.py删掉数据库重新migrate一次。虽然粗暴但开发阶段的成本最低。项目模型一旦定型就不要再删迁移文件了后面每一步都用增量迁移。6.2 DecimalField与JSON序列化的坑上面说了价格要用DecimalField但Django REST Framework在序列化Decimal类型时默认输出的是字符串而不是数字。这在Excel里看没问题但前端ECharts画图时x轴坐标值传字符串图表就会错乱。解决办法是设置序列化器class ProductSerializer(serializers.ModelSerializer): price serializers.DecimalField(max_digits10, decimal_places2, coerce_to_stringFalse) class Meta: model Product fields __all__coerce_to_stringFalse这个参数能让价格以float类型输出到前端。这个细节我当时排查了好久因为后端接口肉眼看起来没问题前端那儿就是显示不出来。6.3 大模型API的超时与并发问题DeepSeek的API调用不是即时的一般响应时间在两秒到五秒之间碰到网络高峰可能更久。所以Django里调用的视图函数超时时间一定要设置的比请求响应时间宽裕不然前端axios默认的超时时间过去请求就会被中断用户就看到网络错误。我的做法是axios统一设置timeout: 15000后端调用大模型时也加超时控制resp client.chat.completions.create( modeldeepseek-chat, messagesmessages, toolsTOOL_DEFINITIONS, timeout10 # 单次调用最多等10秒 )并发方面由于Agent调用链路过长在高并发场景下需要考虑异步化。最朴素的方案是把Agent请求丢进Celery异步队列前端轮询拿结果进阶一点用WebSocket做流式输出。毕设场景不一定需要做到这步但能在答辩时说出如果上线我会用Celery把调用大模型的任务异步化避免阻塞Django的worker进程就是有工程深度了。6.4 Redis缓存的使用时机可视化大屏的统计接口加了Redis缓存之后响应速度直接从秒级降到毫秒级。Django里用cache装饰器或cache.set/get很容易from django.core.cache import cache def sales_trend(request): cached cache.get(sales_trend_30d) if cached: return JsonResponse({data: cached}) # ... 计算逻辑 cache.set(sales_trend_30d, data, 60) return JsonResponse({data: data})一个小技巧是缓存的key要带版本号或参数信息比如sales_trend_{user_id}或者sales_trend_30d避免不同场景之间数据串了。还有一点统计逻辑的结果是JSON字符串直接缓存字符串比缓存对象数组更快更少占内存序列化一次放进去拿出来直接返回。这整个项目做下来核心心得是电商系统本身不难难的是在它上面叠加出有辨识度的东西。数据分析模块让系统从能卖货升级成能指导经营决策大模型Agent让系统从被操作升级成能主动帮你干活这才是这个毕业设计真正值钱的地方。如果你正在做类似的题目先把Django那套业务逻辑做扎实再花时间把可视化和Agent打通完成度会直接上一个台阶。
返回列表