
简介一份面向计算机类毕业设计的家庭大厨微信小程序完整项目采用微信小程序DjangoVueMySQL前后端分离架构。项目覆盖从可行性分析、系统设计到数据库设计、功能实现全过程管理员端包含用户、店铺、菜品信息、菜品分类、购买菜品、订单行及系统管理模块店铺与用户均可在小程序内注册登录并进行菜品浏览和订单操作。整体结构清晰适合作为本科毕业设计改写或学习前后端联调练手。资源包共718个文件大小44.78MB主要包含Vue前端页面、Python/Django后端源码、微信小程序源码、MySQL数据库脚本、毕业论文文档及视频教程另有大量png/svg图标图片、运行所需的bat脚本和配置文件等。前端页面、小程序端与后端逻辑目录分明数据库设计完整附带的安装运行脚本可快速启动项目视频教程则有助于完成环境搭建、功能演示与答辩准备。已有194人学习下载。资料涵盖源码、数据库、论文和视频既可用于论文写作参考也能直接运行体验完整业务流程实用性较强。1. 家庭大厨小程序毕业设计Django Vue MySql 前后端分离的完整源码包每年毕业季都会有人问「有没有一个能直接跑通的微信小程序毕设项目」好用来做参考、改功能、过答辩。这次拆的家庭大厨小程序就是这种定位的工程型资源小程序端负责点菜、看菜谱、下单Django 提供 REST 接口Vue 写后台管理MySql 存数据三个端分开部署但共用一套业务逻辑。它不是玩具 Demo而是按前后端分离的标准结构组织好的完整工程压缩包里带源码、数据库脚本、毕业论文和视频教程基本上把「怎么做出来」到「怎么讲清楚」都覆盖了。适合两类人第一类是拿它当毕设底子的在校生需要快速跑通、看懂流程、再往自己的方向改第二类是刚接触 Django Vue 这套组合的开发者想找一个能少踩坑的实战参考。这篇笔记会按从整体到细节的顺序讲清楚项目结构、运行步骤、核心功能拆解和常见故障处理最后给几个答辩加分和功能扩展的思路。2. 项目结构与选型Django、Vue、MySql 在家庭大厨里各自扮演什么角色2.1 为什么是 Django Vue MySql而不是单体架构老式毕设项目最常见的形式是 Django 直接渲染 HTML 模板模板里带一点 Vue 或 jQuery所有页面都由后端返回。这种方式写起来快但代码耦合重前端改一个小交互就得动 Python 文件。家庭大厨小程序选的是前后端分离Django 只做 API 服务Vue 另起一个工程做后台管理界面微信小程序自带一套前端逻辑三者通过 JSON 格式的 HTTP 接口通信。这个选型的直接好处是三个端可以独立开发、独立启动、独立部署。你在真机上跑小程序后台管理在浏览器里维护菜品数据Django 进程负责读写 MySql任何一个端挂了不影响另外两个。对应到毕设答辩你可以明确讲出这套架构的分层职责这是一个很成熟的加分点。数据流是这样一个链路微信小程序发起请求 → Django 的 REST API 接收并校验 token → ORM 操作 MySql 数据库 → 返回 JSON 给小程序端渲染列表或表单Vue 后台走的是另一套路由和登录态它操作的同样是 Django 暴露的接口但权限角色不同。理解这个链路后面跑联调的时候就不会一头雾水。2.2 从功能模块反推数据库设计用户、菜谱、订单与家庭角色的对应关系拿到数据库脚本先别急着导入花十分钟看表结构比什么都值。家庭大厨的业务场景围绕「家庭」展开所以核心表基本分成四块家庭成员用户表、菜谱信息表、点餐/订单表、家庭成员间的关联表。user 和 member 类表除了常规的 id、用户名、密码哈希还存了家庭成员的角色字段比如爸爸、妈妈、孩子不同角色在小程序端看到的操作入口不一样。recipe 菜谱类表存菜品名称、分类、食材清单、步骤描述、图片 URL、评分字段。图片推荐存路径而不是二进制不然数据库体积会膨胀得很厉害。order 订单类表关联用户表和菜谱表加上下单时间、状态字段。家庭场景下订单不一定真实支付但状态流转还是保留完整。关联表比如收藏表、家庭分组表把用户和菜谱、用户和用户之间的多对多关系拆开。这些表关系在 Django 里对应的是 ForeignKey 和 ManyToManyField。数据库脚本里已经建好了库和示例数据不需要你手动在 Navicat 里逐条创建但你要能说清楚表之间的关联因为这是答辩提问的重灾区。2.3 压缩包内工程分布与关键技术栈对应资源压缩包解压后会看到几个并列目录小程序工程、Django 后端工程、Vue 后台工程外加数据库脚本和论文文档。它们的对应关系是这样小程序端原生微信小程序开发不是 Uniapp。页面包含首页、菜谱列表、菜谱详情、下单页、个人中心接口请求封装在单独的工具文件里请求头统一携带 token。Django 后端Python 3 环境Django 3.x 或更高搭配 Django REST Framework 提供接口。子应用按功能拆分比如用户模块、菜谱模块、订单模块每个子应用有自己的 models、serializers、views。Vue 后台Vue 2 或 Vue 3 要看源码里的 package.json一般用 Element UI 做表格和表单组件。负责菜品的增删改查、订单列表审核、家庭成员管理。数据库脚本一个 .sql 文件包含建库语句、建表语句、示例数据插入语句。导入后用 Django 的 migrate 检查一下模型层和数据库表是否一致。我一般会建议先看 Django 工程下的 urls.py把接口清单打印出来对照着看小程序端的 request 请求发到了哪个 URL 上。这样前后端对应关系会非常清楚远远好过一上来就打开小程序页面看 WXML。项目里如果带接口文档或注释那也是值得优先读的内容。3. 从零跑通环境配置、数据库导入与三端联调的完整流程3.1 环境准备Python、Node、MySql 与微信开发者工具的版本组合跑这套项目需要四个环境Python 解释器、Node.js、MySql 数据库、微信开发者工具。先说版本Django 后端建议用 Python 3.8 到 3.10 之间的版本太新容易遇到第三方库没有预编译 wheel 的情况Vue 后台需要 Node 14 或 16Node 过新会导致 node-sass 这类依赖编译失败MySql 推荐 8.0 以上但要注意 8.0 的默认认证插件是 caching_sha2_password部分老版本 Django 的 MySql 驱动只支持 mysql_native_password这一点后面避坑章节会专门讲。先把 Python 依赖装起来cd django_server pip install -r requirements.txtrequirements.txt 里一般会包含 Django、djangorestframework、django-cors-headers、PyMySQL、Pillow 这些常见包。装完之后在命令行里执行python manage.py runserver如果能正常启动说明基础环境没问题。Vue 后台依赖安装cd vue_admin npm install如果 npm install 中途报错先看一下是不是 node-sass 的版本问题和 Node 版本不匹配。遇到这种情况可以用npm config set sass_binary_site https://npmmirror.com/mirrors/node-sass/把二进制源切到国内镜像再重装。微信小程序端不需要安装依赖直接打开微信开发者工具导入小程序工程目录把 AppID 改成测试号就能看到页面骨架。3.2 MySql 数据库脚本导入与 Django 配置文件的必改位置数据库脚本导入这一步很关键。打开 MySql 命令行或 Navicat先创建一个数据库再把脚本灌进去mysql -u root -p CREATE DATABASE family_cook DEFAULT CHARACTER SET utf8mb4; USE family_cook; SOURCE /your_path/family_cook.sql;导入成功后重点检查三件事登录账号密码字段是不是加密存储、菜谱表里有没有示例数据、外键关联是否完整。这三项正常说明脚本执行得干净。接下来改 Django 的 settings.py数据库连接信息必须和本地匹配DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: family_cook, USER: root, PASSWORD: your_password, HOST: 127.0.0.1, PORT: 3306, OPTIONS: { charset: utf8mb4, }, } }DATABASES 里的 NAME 就是上一步建库的名称USER 和 PASSWORD 换成你自己 MySql 的账号密码。OPTIONS 里强制指定 utf8mb4 是为了防止中文乱码特别是菜谱里带生僻食材名和特殊符号的时候。接着在 settings.py 的 INSTALLED_APPS 里确认有没有注册子应用和 REST Framework 相关配置再执行数据迁移python manage.py makemigrations python manage.py migrate如果脚本建的表结构和模型层一致migrate 执行完不会有任何破坏性提示。如果出现表名冲突或者字段缺失大概率是数据库脚本和源码版本不一致这种问题的处理方式看第 5 章避坑。3.3 三端启动顺序与前后端联调参数联调之前先建立起「三个服务分别跑在哪些端口」的全局观。第一个启动 Django 接口服务跑在 8000 端口第二个启动 Vue 后台开发服务跑在 8080 端口第三个是微信小程序不需要启动本地服务只要保证真机预览或模拟器能访问到 Django 的接口地址即可。先启动 Djangocd django_server python manage.py runserver 0.0.0.0:8000注意这里用了0.0.0.0而不是默认的127.0.0.1。如果小程序用真机预览手机需要通过局域网访问电脑的 IP只有监听 0.0.0.0 才能从外部访问到。模拟器调试用 127.0.0.1 没问题但真机预览必须改。再启动 Vue 后台cd vue_admin npm run serveVue 后台默认跑在 8080 端口如果 8080 被占用Vue CLI 会问你是否换一个端口。启动后打开浏览器访问 localhost:8080能出登录页就是成功的。最后在小程序工程的配置里找到接口地址把 HTTP 请求的 baseURL 从默认值改成你电脑的局域网 IP 加端口// 小程序工具文件里的请求配置 const BASE_URL http://192.168.1.100:8000/api/v1改完之后在微信开发者工具中重新编译模拟器里能看到首页的菜谱列表通过接口拿回了数据三端联调就基本通了。注意这一步不只是改一个字符串要确认你改的这个文件是小程序端所有请求的入口封装有些项目会在每个页面单独写 request那就得逐个改。3.4 请求链路里的 token登录态在小程序与 Django 之间怎么传家庭大厨小程序涉及用户登录和身份识别token 的设计值得单独说。常见方案是手机号或账号密码登录后Django 签发一个 token小程序端缓存起来后续每个请求在 header 里带上# Django 端通过 Django REST Framework 的 TokenAuthentication 实现 from rest_framework.authentication import TokenAuthentication from rest_framework.permissions import IsAuthenticated class RecipeListView(generics.ListAPIView): authentication_classes [TokenAuthentication] permission_classes [IsAuthenticated]对应到小程序端每一次 wx.request 都要带上 token 字段wx.request({ url: BASE_URL /recipes/, header: { Authorization: Token wx.getStorageSync(token) }, success(res) { console.log(res.data) } })这里面容易出问题的点在小程序登录态过期和 token 未同步。Django 签发的 token 如果写到表里有效期不是自动处理的需要你自己在登录接口里做校验。另外Vue 后台登录用的是另一套 session 或 token 机制不要和小程序的 token 混用各自的请求头字段可以不一样两端独立认证。4. 核心功能拆解菜谱列表、收藏下单与 Vue 后台管理的实现思路4.1 菜谱列表分页加载小程序端怎么把接口数据渲染到页面上家庭大厨小程序首页的核心场景是菜谱列表数据量大了不能一次性全返回所以接口要做分页。Django 端用 REST Framework 的 PageNumberPagination小程序端在页面翻到底部时自动加载下一页。先看 Django 端的接口分页配置# Django 端settings.py 里统一设置分页类 REST_FRAMEWORK { DEFAULT_PAGINATION_CLASS: rest_framework.pagination.PageNumberPagination, PAGE_SIZE: 10 }这里 PAGE_SIZE 设为 10表示每页最多返回 10 条菜谱记录。接口返回的 JSON 结构会包含 count、next、previous 和 results 四部分小程序端解析 next 字段判断还有没有下一页。小程序端页面 JS 的逻辑是维护一个 currentPage 变量onReachBottom 里触发当前页码加一并发起请求新请求返回的数据追加到列表数组尾部而不是替换掉整组数据// 小程序端分页加载 data: { recipeList: [], currentPage: 1, hasMore: true, loading: false }, onReachBottom() { if (!this.data.hasMore || this.data.loading) return this.setData({ loading: true, currentPage: this.data.currentPage 1 }) this.fetchRecipes() }, fetchRecipes() { const page this.data.currentPage wx.request({ url: BASE_URL /recipes/?page page, header: { Authorization: Token wx.getStorageSync(token) }, success: (res) { const newList this.data.recipeList.concat(res.data.results) this.setData({ recipeList: newList, hasMore: res.data.next ! null, loading: false }) } }) }这段代码里的 onReachBottom 是微信小程序的页面触底生命周期它的触发条件跟页面布局有关——如果页面内容高度不够一屏触底事件根本不会触发这是常见排查点。concat 是数组合并操作把老数据和新增数据拼接到一起同时更新 hasMore 标志位。如果接口里没有 next 字段说明后端没启用分页先检查 Django 端的配置再回来调前端。4.2 收藏和点赞Django ORM 查询与关系字段的外键处理家庭大厨小程序里的收藏功能核心是用户和菜谱的多对多关系表设计上收藏表专门存放 userId 和 recipeId。Django 端用 ORM 做一对一或一对多的查询非常方便不需要拼 SQL# Django 端收藏接口的视图逻辑 from rest_framework.decorators import api_view from .models import Favorite, Recipe api_view([POST]) def add_favorite(request): user request.user recipe_id request.data.get(recipe_id) if Favorite.objects.filter(useruser, recipe_idrecipe_id).exists(): Favorite.objects.get(useruser, recipe_idrecipe_id).delete() return Response({msg: 已取消收藏, status: False}) Favorite.objects.create(useruser, recipe_idrecipe_id) return Response({msg: 收藏成功, status: True})Favorite.objects.filter 判断是否已存在这里用了 exists() 而不是 count()因为判断存在性时 exists 的 SQL 更轻量。如果已收藏就删除这条记录实现「再次点击取消收藏」的切换交互没有收藏则新建记录。为什么会把删除和创建放在同一个接口里是为了减少接口数量小程序端不用分别调用 add 和 remove 两个 URL。需要注意的一个细节是Favorite.objects.get(useruser, recipe_idrecipe_id)在记录不存在时会抛 DoesNotExist 异常但前面已用 filter 做了存在性判断所以不会有问题。正确顺序是 filter 判断 → 存在才 get → 不存在则 create这个顺序写反会出 500 错误。4.3 Vue 后台的菜品管理表格渲染、表单编辑与图片上传流程Vue 后台管理页面是给家庭管理员用的核心操作是菜谱维护——新增菜品、编辑菜谱步骤、删除过期菜品。页面结构通常是一个表格加一个弹窗表单表格列绑定菜谱字段表单字段对应新增和编辑接口。Element UI 表格绑定的数据源来自 Django 接口mounted 阶段请求菜谱列表// Vue 后台的菜品列表 mounted() { this.fetchRecipes() }, methods: { async fetchRecipes() { const res await axios.get(/api/v1/recipes/, { headers: { Authorization: Bearer localStorage.getItem(admin_token) } }) this.tableData res.data.results } }axios 是 Vue 项目里最常用的 HTTP 请求库它和小程序的 wx.request 不一样Vue 使用 axios 时通常会在 main.js 里全局配置 baseURL 和拦截器token 在拦截器里统一注入到请求头不需要每个请求单独写 headers。图片上传是后台管理中比较容易出问题的模块。Vue 端先通过 Element UI 的 upload 组件把图片发送到 Django 的图片上传接口Django 端接收后返回图片 URL 字符串前端拿到这个 URL 存入表单再跟随菜品数据一起提交# Django 端图片上传接口 api_view([POST]) def upload_image(request): file request.FILES.get(file) if not file: return Response({msg: 未收到图片}, status400) # 实际项目中建议按日期分目录存储 file_path handle_uploaded_file(file) return Response({url: file_path, msg: 上传成功})这里 handle_uploaded_file 一般是用 Django 的 FileSystemStorage 把文件写到 MEDIA_ROOT 下同时在数据库里只存相对路径。要注意 Django 的静态文件服务和媒体文件服务是两套逻辑开发环境下要单独配置 MEDIA_URL 的映射不然浏览器访问不到上传后的图片地址。这部分是可以直接抄的代码但漏配一个 url 就会让所有菜品图片显示成破图。5. 避坑记录跑通这套家庭大厨项目最常遇到的六个故障5.1 坑一MySql 8.0 认证插件导致 Django 连接数据库报错报错现象是 Django 启动后执行 migrate 或任何数据库操作直接抛django.db.utils.OperationalError: (1045, Access denied for user rootlocalhost)这类认证失败信息。原因是 MySql 8.0 默认的认证插件是 caching_sha2_password而 Django 用的 PyMySQL 老版本默认走的是 mysql_native_password 协议。解决方式有两个路径第一个是把 MySql 用户认证改回旧协议第二个是升级 PyMySQL 到足够新的版本。优先尝试第二个执行pip install PyMySQL --upgrade升级完再重启 Django 服务看看。如果还是报错再用 SQL 改认证插件ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY your_password; FLUSH PRIVILEGES;要注意改认证插件会影响所有通过此账号连接的客户端改之前确认你清楚当前所有依赖它的服务。5.2 坑二微信开发者工具提示「不在以下 request 合法域名列表中」报错通常长这样xxx不在以下 request 合法域名列表中请参考文档。这是微信平台对小程序请求地址的限制——正式版小程序只能请求配置过白名单的 https 域名。本地联调时你用的是 http 加局域网 IP当然不在白名单里。解决方式是在微信开发者工具的「详情 → 本地设置」里勾选「不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书」。这个选项只对当前开发者工具实例生效真机预览得用调试模式。如果真机预览仍然被拦截检查一下手机和电脑是不是在同一局域网内IP 地址是否写成了 127.0.0.1。5.3 坑三Django 跨域中间件配置之后请求还是被浏览器拦截Vue 后台访问 Django 接口时会遇到跨域问题报错提示是 CORS 头缺失。原因是前端服务跑在 8080Django 跑在 8000浏览器默认禁止跨端口的中跨域请求。配置 django-cors-headers 之后仍然不生效最常见的错误是把中间件插件放到了 MIDDLEWARE 列表里靠后的位置。跨域头必须在所有视图逻辑之前设置因此 CorsMiddleware 要放在尽可能靠前的位置至少要排在 CommonMiddleware 前面。MIDDLEWARE [ corsheaders.middleware.CorsMiddleware, django.middleware.security.SecurityMiddleware, # 保证 CorsMiddleware 在列表前部 ]另一个遗漏是CORS_ALLOWED_ORIGINS或CORS_ORIGIN_ALLOW_ALL没有配置。如果源码里用的是白名单记得把http://localhost:8080加进去如果你只是本地调试直接用CORS_ORIGIN_ALLOW_ALL True省心。5.4 坑四sql 脚本导入后中文数据乱码或插入失败导入 MySql 脚本时Navicat 或命令行执行完毕查表看到菜品名称全是问号或者是导入直接报字符串截断错误。原因通常是脚本内没有指定字符集或 MySql 客户端默认字符集不是 utf8mb4。命令行导入时强制指定字符集能解决大部分问题mysql -u root -p --default-character-setutf8mb4 family_cook family_cook.sql导入之前也先确认一下库的默认字符集ALTER DATABASE family_cook CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;。如果脚本里每个表的建表语句没有显式声明 CHARSET建表时会沿用库级默认值库级默认错误会导致所有表一起遭殃。5.5 Vue 后台打包后刷新页面 404路由 mode 配置问题的经典翻车Vue 后台在开发模式下一切正常但npm run build打包后部署到服务器点一个链接没问题按 F5 刷新就白屏或 404。原因是 Vue Router 默认用了 history 模式刷新时浏览器请求了服务器上不存在的真实路径服务器没有做重定向。如果是本地开发环境最简单的临时处理是在 Vue Router 配置里把 mode 改为 hash路由链接会带/#/后缀刷新 404 现象消失如果是给毕设答辩做演示不涉及生产部署这个方案完全够用。const router new VueRouter({ mode: hash, // 开发调试用 hash 最省心 routes })生产环境就该让 Nginx 把所有路由请求指向 index.htmllocation / { try_files $uri $uri/ /index.html; }。但如果你的 Nginx 不熟悉建议答辩期间用 hash 模式避免在环境配置上消耗太多时间等论文里专门写静态部署部分时再研究。5.6 小程序页面下拉没反应、触底加载不触发先看页面高度再排代码小程序里 onReachBottom 不触发的原因有一半以上和请求代码无关而是页面整体高度小于屏幕可视高度。触底事件要求页面必须有滚动容器整个内容区撑不满一屏时不会产生滚动自然没有触底。排查时先把页面内容临时填充到很长确认触底事件能触发再逐步删减内容定位问题。另一个隐蔽点在分页游标的同步顺序——onReachBottom 里先更新 currentPage 再调用请求函数如果请求函数是高并发触发两次页面会出现重复列表数据。处理方式是在请求前置一个 loading 标志锁请求完成后再解开代码在第四章分页示例里已经体现过。6. 验证与进阶把这三端工程变成能讲清楚、能扩展的东西跑通只是第一步毕业设计要的是「能演示、能讲、能改」。我建议从一套验收清单开始按用户故事过一遍所有主流程在微信小程序里注册新用户、浏览菜谱列表、查看菜谱详情、收藏一道菜、下一单再到 Vue 后台登录管理员账号、新增菜品、编辑价格和步骤、处理订单状态。每一步有问题就直接定位到对应日志Django 端看 runserver 的终端输出小程序端看 console 面板Vue 端看浏览器 Network 标签。这套流程走完说明三端联调是真正通了而不是只看首页加载能出数据。验收通过之后有余力的话我强烈建议在答辩前加一个不影响现有主流程的小功能点。性价比比较高的方向有三个第一个是菜谱搜索接口Django 端用 Django ORM 的 icontains 按菜名和食材做模糊查询小程序端加一个搜索框代码量小而且很好讲第二个是家庭多人协作的场景给菜品打标签比如「孩子爱吃」「少辣」Django 加一个标签字段Vue 后台做成多选框第三个是给订单状态加一个统计页Vue 后台用 ECharts 画一个柱状图展示一周内家庭点餐偏好这个视觉效果好答辩时讲解价值最大化。每加一个功能都改在这个基准工程上不要另开一套代码也不要破坏原本的接口结构——Django 的多子应用结构允许你新增一个 app 而不动原有模块小程序端新增页面也不会影响现有页面逻辑。这个扩展意识本身在答辩中就是「工程素养」层面的加分项比自己背熟项目代码有用得多。最后说个我的习惯每次跑毕设工程我都会把改动过的文件列一个清单放在项目根目录的 CHANGES.md 里记录改了哪个文件、为什么改、改之前的现象是什么。答辩时老师问到「这个数据库连接超时你是怎么排查的」你直接翻文件说出上下文比临时想强太多。这套家庭大厨工程虽然不是为每个人定制但它的结构足够标准改造成本很低希望帮到你。本文还有配套的精品资源点击获取