尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于微信小程序与Django的全栈毕业设计实战:家庭菜谱系统开发指南

基于微信小程序与Django的全栈毕业设计实战:家庭菜谱系统开发指南 简介全栈开发是构建现代Web应用的核心模式它通过前后端分离的架构将用户界面与业务逻辑解耦从而提升开发效率和系统可维护性。其原理在于前端负责数据展示与交互后端提供API接口进行数据处理两者通过HTTP协议通信。这种模式的技术价值在于支持团队并行开发、技术栈灵活选型以及更好的用户体验。在应用场景上全栈开发广泛适用于电商平台、内容管理系统和社交应用等。本文以微信小程序、Django、Vue和MySQL构建的“家庭菜谱分享系统”为例深入剖析了前后端分离项目实战的具体实现涵盖了从数据库设计、RESTful API构建到小程序分包异步化等性能优化策略为计算机专业学生完成毕业设计提供了完整的工程实践路径。1. 项目缘起一个“家庭大厨”的诞生记去年年底我的一位学弟找到我说他的毕业设计选题是做一个关于家庭菜谱分享的小程序技术栈想用微信小程序、Django、Vue和MySQL走前后端分离的路子。他手头有老师给的一个非常粗略的需求文档但具体怎么落地从技术选型到代码实现再到最后的论文撰写和部署完全是一头雾水。他问我能不能给点思路或者有没有现成的项目可以参考。说实话市面上教单一技术的教程很多比如“Django从入门到精通”、“Vue3实战”之类的但能把微信小程序、Django后端、Vue管理后台、MySQL数据库以及毕业设计特有的文档论文、源码、部署脚本全部串起来形成一个完整闭环的实战项目确实不多见。大多数教程要么只讲前端要么只讲后端对于需要独立完成一个完整应用、尤其是作为毕业设计的同学来说中间有太多的“沟壑”需要自己填平。正是基于这个契机我决定和他一起把这个“家庭大厨”小程序从零到一地做出来并且把整个过程、踩过的坑、核心的代码逻辑以及最终打包好的所有材料源码、数据库脚本、毕业论文框架、录制的关键环节视频都系统地整理出来。这不仅仅是一个项目更是一份为计算机相关专业同学量身定制的“毕业设计实战指南”。无论你是对其中某一项技术不熟还是对整个全栈开发流程感到迷茫这个项目都能给你提供一个清晰的、可复现的路径。2. 技术栈深度剖析为什么是它们在开始敲代码之前搞清楚为什么选择这套技术组合至关重要。这决定了项目的架构是否合理以及后续开发是否会顺畅。很多同学做项目是“为了用技术而用技术”最后发现组合起来特别别扭。我们这个“家庭大厨”的选择是经过实际场景推敲的。2.1 微信小程序触达用户的轻量级入口家庭菜谱的核心用户是谁是每一个在厨房里忙碌或者想学做菜的人。他们需要的是一个能随时打开、快速浏览、收藏菜谱的工具。原生App开发成本高推广难纯H5页面体验和能力如本地存储、扫码又受限制。微信小程序几乎是完美选择无需安装即用即走用户扫个码或者搜一下就能用转化路径极短。生态成熟能力丰富提供了完善的登录微信一键登录、支付、云存储、地理位置等API我们菜谱的“根据定位推荐本地美食”功能就能轻松实现。开发体验友好基于JavaScript/TypeScript和自有的组件框架对于有前端基础的同学上手很快。而且小程序分包异步化这个特性我们后面会重点用到它是解决小程序体积限制、提升首次加载速度的关键。2.2 Django稳健高效的“后勤部长”后端为什么选Django而不是更“新潮”的FastAPI或Spring Boot对于毕业设计和一个快速迭代的全栈项目Django的“开箱即用”和“功能全面”是巨大优势。Admin后台秒出Django自带的Admin站点几乎不用写前端代码就能得到一个功能强大的数据管理后台。在项目初期我们可以直接用它来管理用户、菜谱、分类等数据快速验证业务逻辑。虽然我们最终会用Vue写一个更美观的管理后台但Django Admin在开发阶段的效率无可替代。ORM强大避免裸写SQLDjango的ORM对象关系映射让操作数据库像操作Python对象一样简单。对于大多数毕业设计级别的数据操作ORM完全够用而且更安全避免SQL注入、更易维护。定义好Recipe菜谱、Category分类模型复杂的关联查询几句代码就能搞定。生态与安全性Django有成熟的用户认证系统、表单验证、中间件、安全防护如CSRF、XSS防护。国内Python Web开发中Django的占有率非常高社区活跃遇到问题容易找到解决方案。很多人问“python django国内使用广泛么”答案是肯定的尤其在传统企业、高校和快速开发领域它依然是主力之一。2.3 Vue.js构建优雅的管理后台既然后端用了Django为什么管理后台不直接用Django的模板而要引入Vue做前后端分离这是为了追求更好的用户体验和开发体验。前后端职责彻底分离后端Django只提供纯粹的RESTful API我们用Django REST framework前端Vue负责所有页面渲染和交互。这样前后端开发可以并行API定义好接口文档即可。这也是前后端分离项目实战的核心思想。响应式与组件化管理后台通常有复杂的表单、表格和图表。Vue的响应式数据绑定和组件化开发能让这些交互复杂的页面开发起来更高效代码也更易复用和维护。比如一个封装好的“菜谱上传”组件可以在多个页面使用。丰富的生态系统Vue有Vue Router处理路由Vuex或Pinia管理状态还有Element Plus、Ant Design Vue等优秀的UI库能让我们快速搭建出专业美观的管理界面。关于vue播放m3u8如果未来需要在小程序或后台集成视频教程播放我们可以将视频转码为M3U8格式并使用vue-video-player等插件配合hls.js库来实现流媒体播放。2.4 MySQL久经考验的数据仓库数据库的选择相对直接。MySQL作为最流行的开源关系型数据库稳定、性能好、生态完善。与Django天生一对Django官方对MySQL支持非常好配置几行代码即可连接。事务与复杂查询支持菜谱系统可能会有“发布菜谱-上传图片”这样的需要事务保证一致性的操作MySQL完全胜任。对于菜谱的复杂筛选按食材、口味、难度利用好索引MySQL也能高效处理。学习与部署成本低相关教程mysql安装教程,mysql安装配置教程遍地都是云服务商提供的RDS服务也大多以MySQL为主后期部署上线非常方便。总结一下技术选型逻辑微信小程序负责面向用户的轻量级前端Django作为大后方的API服务器和快速原型工具Vue构建给管理员用的、交互丰富的运营后台MySQL作为可靠的数据存储。这套组合兼顾了开发效率、性能、用户体验和学习成本是完成一个高质量毕业设计的黄金组合。3. 核心功能设计与数据库建模一个项目能否立得住看它的核心功能设计能否高效运行看它的数据库模型。我们围绕“家庭大厨”的核心——菜谱来展开设计。3.1 用户故事与功能模块我们从一个普通用户“小王”的视角来梳理功能小王打开小程序他可以选择微信一键登录系统会记录他的偏好比如爱吃辣。浏览与发现首页给他推荐热门菜谱、今日精选。他可以通过顶部的搜索框这里会涉及微信小程序顶部导航栏高度的自适应调整找“红烧肉”也可以通过分类家常菜、烘焙、川菜或标签快手菜、下饭菜筛选。查看菜谱详情点开一个菜谱能看到详细的步骤图、文字说明、所需食材清单支持一键加入购物车清单、烹饪技巧。还有点赞、收藏、评论功能。互动与创作小王收藏了喜欢的菜谱。他也可以上传自己的独创菜谱填写信息、上传步骤图。管理后台管理员视角管理员登录Vue开发的后台可以审核用户提交的菜谱、管理用户评论、配置首页轮播图、查看系统数据统计等。基于以上我们划分出核心模块用户模块、菜谱模块核心、分类/标签模块、互动点赞/收藏/评论模块、后台管理模块。3.2 数据库表结构设计MySQL使用Django的ORM我们首先在models.py中定义模型这直接决定了数据库表的结构。以下是几个核心模型的设计思路和部分字段# models.py from django.db import models from django.contrib.auth.models import AbstractUser # 1. 用户模型继承Django内置用户增加字段 class User(AbstractUser): avatar models.URLField(头像, blankTrue, default) # 存储微信头像URL wechat_openid models.CharField(微信OpenID, max_length100, uniqueTrue, blankTrue, nullTrue) # 微信唯一标识 bio models.TextField(个人简介, blankTrue) favorite_cuisine models.CharField(偏好口味, max_length50, blankTrue) class Meta: db_table user # 自定义表名 # 2. 菜谱分类 class Category(models.Model): name models.CharField(分类名, max_length20) icon models.CharField(图标类名, max_length50, blankTrue) # 用于前端显示图标 order models.IntegerField(排序, default0) def __str__(self): return self.name # 3. 菜谱标签多对多 class Tag(models.Model): name models.CharField(标签名, max_length10) # 4. 核心菜谱模型 class Recipe(models.Model): DIFFICULTY_CHOICES ( (1, 简单), (2, 中等), (3, 困难), ) title models.CharField(菜谱标题, max_length100) cover_image models.URLField(封面图) # 图片上传后得到URL存到这里 description models.TextField(描述) ingredients models.TextField(食材清单) # 可以用JSON格式存储这里简化为文本 steps models.JSONField(步骤) # 重要使用JSONField存储步骤数组每个步骤包含文字和图片URL tips models.TextField(小贴士, blankTrue) cooking_time models.IntegerField(烹饪时间(分钟)) difficulty models.IntegerField(难度, choicesDIFFICULTY_CHOICES, default1) # 外键关联 author models.ForeignKey(User, on_deletemodels.CASCADE, related_namerecipes, verbose_name作者) category models.ForeignKey(Category, on_deletemodels.SET_NULL, nullTrue, related_namerecipes, verbose_name分类) tags models.ManyToManyField(Tag, blankTrue, related_namerecipes, verbose_name标签) # 统计字段 view_count models.IntegerField(浏览量, default0) like_count models.IntegerField(点赞数, default0) collect_count models.IntegerField(收藏数, default0) # 状态与时间 is_approved models.BooleanField(审核通过, defaultFalse) # 后台审核用 created_at models.DateTimeField(创建时间, auto_now_addTrue) updated_at models.DateTimeField(更新时间, auto_nowTrue) class Meta: db_table recipe ordering [-created_at] # 默认按创建时间倒序 # 5. 用户-菜谱互动关系点赞、收藏 class UserRecipeInteraction(models.Model): INTERACTION_TYPE ( (like, 点赞), (collect, 收藏), ) user models.ForeignKey(User, on_deletemodels.CASCADE) recipe models.ForeignKey(Recipe, on_deletemodels.CASCADE) interaction_type models.CharField(互动类型, max_length10, choicesINTERACTION_TYPE) created_at models.DateTimeField(auto_now_addTrue) class Meta: db_table user_recipe_interaction unique_together (user, recipe, interaction_type) # 防止重复点赞/收藏设计要点与避坑指南steps字段使用JSONField这是关键。一个菜谱的步骤是动态的每个步骤有文字和可能的多张图片。用JSON字段存储一个列表[{text: 第一步..., images: [url1, url2]}, ...]比再拆一个Step表更灵活查询也更高效。Django的ORM支持对JSONField进行查询。使用unique_together确保同一个用户对同一个菜谱只能点赞或收藏一次。这是业务逻辑的保证在数据库层面做约束最可靠。统计字段冗余like_count,collect_count是冗余字段。每次查询都去UserRecipeInteraction表联表统计count效率太低。我们通过监听点赞/收藏动作的信号Django Signals来实时更新这些计数。这是一种“用空间换时间”的常见优化。图片存储cover_image和steps里的图片URL我们通常不上传到Django项目本身而是上传到云存储如腾讯云COS、七牛云。Django端只保存最终的文件访问URL。这涉及文件上传API的设计后面会讲。4. 前后端分离架构实战API、小程序与Admin这是项目的核心骨架。我们将系统拆分为三个部分Django API后端、微信小程序前端、Vue管理后台。它们之间通过HTTP API进行通信。4.1 Django后端构建RESTful API我们使用Django REST framework (DRF)这个强力工具来快速构建API。首先定义序列化器Serializer它负责将模型实例转换为JSON数据以及将客户端提交的JSON数据验证并转换为模型实例。# serializers.py from rest_framework import serializers from .models import Recipe, Category, User class CategorySerializer(serializers.ModelSerializer): class Meta: model Category fields [id, name, icon] class UserSimpleSerializer(serializers.ModelSerializer): class Meta: model User fields [id, username, avatar] class RecipeListSerializer(serializers.ModelSerializer): # 嵌套序列化在列表页显示分类名和作者名而不是ID category CategorySerializer(read_onlyTrue) author UserSimpleSerializer(read_onlyTrue) # 计算字段当前登录用户是否已点赞/收藏 is_liked serializers.SerializerMethodField() is_collected serializers.SerializerMethodField() class Meta: model Recipe fields [id, title, cover_image, description, cooking_time, difficulty, view_count, like_count, collect_count, category, author, is_liked, is_collected, created_at] def get_is_liked(self, obj): request self.context.get(request) if request and request.user.is_authenticated: return obj.interactions.filter(userrequest.user, interaction_typelike).exists() return False def get_is_collected(self, obj): # 类似上面的逻辑 ... class RecipeDetailSerializer(RecipeListSerializer): # 详情页序列化器继承列表页的并增加更多字段 steps serializers.JSONField() # 直接输出JSON ingredients serializers.CharField() tags TagSerializer(manyTrue, read_onlyTrue) class Meta(RecipeListSerializer.Meta): fields RecipeListSerializer.Meta.fields [steps, ingredients, tags, tips]接着编写视图集ViewSet它封装了常见的列表、详情、创建、更新、删除等操作。# views.py from rest_framework import viewsets, permissions, status, filters from rest_framework.decorators import action from rest_framework.response import Response from django_filters.rest_framework import DjangoFilterBackend from .models import Recipe from .serializers import RecipeDetailSerializer, RecipeListSerializer from .permissions import IsAuthorOrReadOnly # 自定义权限只有作者能修改 class RecipeViewSet(viewsets.ModelViewSet): 菜谱视图集。 列表和详情所有人可读。 创建需登录。 更新/删除需是作者本人。 queryset Recipe.objects.filter(is_approvedTrue) # 默认只返回审核通过的 permission_classes [permissions.IsAuthenticatedOrReadOnly, IsAuthorOrReadOnly] filter_backends [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] filterset_fields [category, difficulty] # 精确过滤 search_fields [title, description, ingredients] # 搜索 ordering_fields [created_at, like_count, view_count] # 排序 def get_serializer_class(self): # 根据动作选择不同的序列化器 if self.action list: return RecipeListSerializer return RecipeDetailSerializer def perform_create(self, serializer): # 创建菜谱时自动将当前登录用户设为作者 serializer.save(authorself.request.user) action(detailTrue, methods[post], permission_classes[permissions.IsAuthenticated]) def like(self, request, pkNone): 点赞/取消点赞 recipe self.get_object() user request.user interaction, created UserRecipeInteraction.objects.get_or_create( useruser, reciperecipe, interaction_typelike ) if not created: # 如果已存在则是取消点赞 interaction.delete() recipe.like_count max(0, recipe.like_count - 1) liked False else: recipe.like_count 1 liked True recipe.save() return Response({liked: liked, count: recipe.like_count}) # 类似地可以实现 collect收藏action最后在urls.py中注册路由。# urls.py (api app) from django.urls import path, include from rest_framework.routers import DefaultRouter from . import views router DefaultRouter() router.register(rrecipes, views.RecipeViewSet) # 可以继续注册其他视图集如 categories, tags urlpatterns [ path(, include(router.urls)), # 微信登录接口 path(wechat-login/, views.WechatLoginView.as_view(), namewechat-login), # 文件上传接口 path(upload-image/, views.UploadImageView.as_view(), nameupload-image), ]关键点解析权限控制使用DRF的permission_classes和自定义权限类如IsAuthorOrReadOnly可以精细控制每个API的访问权限。过滤、搜索、排序通过配置filter_backends几行代码就为列表API增加了强大的查询能力前端传参如?category1search红烧肉ordering-like_count即可。自定义Actionaction装饰器让我们能在视图集上添加像/recipes/{id}/like/这样的自定义端点处理点赞等特定业务逻辑非常清晰。微信登录WechatLoginView会接收小程序端传来的code调用微信接口换取openid和session_key然后在自己的数据库中查找或创建用户并返回自定义的Token如JWT给小程序。这是小程序登录的标准流程。4.2 微信小程序前端关键实现与优化小程序端我们使用原生的JavaScript/TypeScript和WXML/WXSS开发。这里讲几个核心和易错点。1. 网络请求封装与鉴权 小程序所有网络请求必须走HTTPS。我们需要封装wx.request统一添加加载状态、错误处理和请求头如携带Token。// utils/request.js const BASE_URL https://your-api-domain.com/api; const request (options) { // 显示加载中 wx.showLoading({ title: 加载中..., mask: true }); return new Promise((resolve, reject) { wx.request({ url: BASE_URL options.url, method: options.method || GET, data: options.data, header: { Content-Type: application/json, Authorization: Bearer ${wx.getStorageSync(token)} // 从本地存储获取Token }, success: (res) { wx.hideLoading(); if (res.statusCode 200) { resolve(res.data); } else { // 处理HTTP错误码如401跳转登录 handleError(res); reject(res); } }, fail: (err) { wx.hideLoading(); wx.showToast({ title: 网络错误, icon: none }); reject(err); } }); }); }; // 使用示例获取菜谱列表 export const getRecipes (params) request({ url: /recipes/, method: GET, data: params }); // 使用示例点赞 export const likeRecipe (recipeId) request({ url: /recipes/${recipeId}/like/, method: POST });2. 图片上传与预览 菜谱创建时的图片上传是重头戏。小程序提供了wx.chooseMedia选择图片wx.uploadFile上传文件。// pages/publish/publish.js Page({ data: { steps: [{ text: , images: [] }], // 步骤数据 }, // 为某个步骤添加图片 addStepImage(stepIndex) { wx.chooseMedia({ count: 3, // 一次最多选3张 mediaType: [image], success: (res) { const tempFiles res.tempFiles; // 先在前端预览 const newImages tempFiles.map(file file.tempFilePath); const key steps[${stepIndex}].images; this.setData({ [key]: this.data.steps[stepIndex].images.concat(newImages) }); // 然后逐一上传到服务器 newImages.forEach(tempFilePath { this.uploadImage(tempFilePath).then(serverUrl { // 上传成功将临时路径替换为服务器URL这里需要更新data略 }); }); } }); }, uploadImage(tempFilePath) { return new Promise((resolve, reject) { wx.uploadFile({ url: ${BASE_URL}/upload-image/, filePath: tempFilePath, name: file, header: { Authorization: Bearer ${wx.getStorageSync(token)} }, success: (res) { const data JSON.parse(res.data); if (data.success) { resolve(data.url); // 服务器返回的图片URL } else { reject(data.message); } }, fail: reject }); }); }, });注意小程序上传文件到DjangoDjango端需要使用request.FILES来接收并妥善处理文件名、文件大小限制、文件类型验证最后将文件保存到云存储或本地返回可访问的URL。3. 性能优化分包异步化小程序主包大小限制为2M。随着项目功能增多很容易超限。分包异步化是必须掌握的技能。原则将非首页必需的页面如个人中心、菜谱发布页、设置页和其独有的组件、静态资源打到独立的分包中。配置在app.json中配置subpackages。// app.json { pages: [ pages/index/index, // 主包页面 pages/recipeDetail/recipeDetail ], subpackages: [ { root: packageUser, pages: [ pages/profile/profile, pages/myRecipes/myRecipes ] }, { root: packagePublish, pages: [ pages/publish/publish ] } ] }异步化在需要跳转到分包页面时使用wx.navigateTo正常跳转即可小程序会在需要时自动下载该分包。对于分包内的自定义组件在引用时也需要在对应页面的json文件中声明usingComponents并确保组件在分包目录内。4. 样式与布局导航栏高度适配不同手机型号的顶部导航栏包括状态栏高度不同。为了做出沉浸式效果或精确布局我们需要动态获取这个高度。// app.js 或工具函数中 const getSystemInfo () { const systemInfo wx.getSystemInfoSync(); const statusBarHeight systemInfo.statusBarHeight; // 状态栏高度 const menuButtonInfo wx.getMenuButtonBoundingClientRect(); // 胶囊按钮信息 // 导航栏总高度 ≈ 状态栏高度 (胶囊按钮上边距 - 状态栏高度) * 2 胶囊按钮高度 const navBarHeight statusBarHeight (menuButtonInfo.top - statusBarHeight) * 2 menuButtonInfo.height; return { statusBarHeight, navBarHeight }; }; // 在页面中设置到data用于WXSS样式 Page({ data: { navBarHeight: 0, statusBarHeight: 0 }, onLoad() { const { navBarHeight, statusBarHeight } getSystemInfo(); this.setData({ navBarHeight, statusBarHeight }); } })/* 页面WXSS */ .custom-nav-bar { height: {{navBarHeight}}px; padding-top: {{statusBarHeight}}px; box-sizing: content-box; }4.3 Vue管理后台高效的数据驾驶舱管理后台我们使用Vue 3 Element Plus Axios。它通过调用相同的Django REST API来管理数据。1. 核心页面菜谱管理这是一个典型的CRUD列表页包含搜索、筛选、分页、审核、编辑、删除等操作。!-- RecipeManagement.vue -- template div el-card !-- 搜索和筛选区域 -- el-form :inlinetrue :modelsearchForm el-form-item label标题 el-input v-modelsearchForm.title placeholder请输入标题 clearable / /el-form-item el-form-item label分类 el-select v-modelsearchForm.category placeholder请选择分类 clearable el-option v-forcat in categories :keycat.id :labelcat.name :valuecat.id / /el-select /el-form-item el-form-item label审核状态 el-select v-modelsearchForm.is_approved placeholder请选择状态 clearable el-option label已审核 :valuetrue / el-option label待审核 :valuefalse / /el-select /el-form-item el-form-item el-button typeprimary clickhandleSearch搜索/el-button el-button clickresetSearch重置/el-button /el-form-item /el-form /el-card el-card stylemargin-top: 20px; !-- 数据表格 -- el-table :datarecipeList v-loadingloading el-table-column propid labelID width80 / el-table-column proptitle label标题 / el-table-column propauthor.username label作者 / el-table-column propcategory.name label分类 / el-table-column propview_count label浏览量 width100 / el-table-column label审核状态 width100 template #default{ row } el-tag :typerow.is_approved ? success : warning {{ row.is_approved ? 已通过 : 待审核 }} /el-tag /template /el-table-column el-table-column label操作 width200 fixedright template #default{ row } el-button sizesmall clickhandleView(row)查看/el-button el-button sizesmall typeprimary clickhandleApprove(row) v-if!row.is_approved通过/el-button el-button sizesmall typedanger clickhandleDelete(row)删除/el-button /template /el-table-column /el-table !-- 分页 -- el-pagination stylemargin-top: 20px; justify-content: center; v-model:current-pagecurrentPage v-model:page-sizepageSize :page-sizes[10, 20, 50] layouttotal, sizes, prev, pager, next, jumper :totaltotal size-changehandleSizeChange current-changehandleCurrentChange / /el-card !-- 详情/编辑对话框 -- el-dialog v-modeldialogVisible title菜谱详情 width80% !-- 对话框内容展示或编辑菜谱详情 -- div v-ifcurrentRecipe h2{{ currentRecipe.title }}/h2 p作者{{ currentRecipe.author.username }}/p !-- 更多详情展示 -- div v-for(step, index) in currentRecipe.steps :keyindex h4步骤 {{ index 1 }}/h4 p{{ step.text }}/p img v-forimg in step.images :srcimg :keyimg stylewidth: 100px; margin: 5px; / /div /div template #footer span classdialog-footer el-button clickdialogVisible false关闭/el-button el-button typeprimary clickdialogVisible false确定/el-button /span /template /el-dialog /div /template script setup import { ref, onMounted } from vue; import { getRecipeList, approveRecipe, deleteRecipe } from /api/recipe; import { ElMessage, ElMessageBox } from element-plus; const searchForm ref({ title: , category: , is_approved: }); const recipeList ref([]); const loading ref(false); const currentPage ref(1); const pageSize ref(10); const total ref(0); const dialogVisible ref(false); const currentRecipe ref(null); const loadData async () { loading.value true; try { const params { page: currentPage.value, page_size: pageSize.value, ...searchForm.value }; // 移除空值参数 Object.keys(params).forEach(key { if (params[key] || params[key] null || params[key] undefined) { delete params[key]; } }); const res await getRecipeList(params); recipeList.value res.results; // DRF分页返回 results 和 count total.value res.count; } catch (error) { ElMessage.error(获取数据失败); } finally { loading.value false; } }; const handleSearch () { currentPage.value 1; loadData(); }; const resetSearch () { searchForm.value { title: , category: , is_approved: }; handleSearch(); }; const handleSizeChange (val) { pageSize.value val; loadData(); }; const handleCurrentChange (val) { currentPage.value val; loadData(); }; const handleApprove async (row) { try { await approveRecipe(row.id); ElMessage.success(审核通过); row.is_approved true; // 更新本地数据 } catch (error) { ElMessage.error(操作失败); } }; const handleDelete (row) { ElMessageBox.confirm(确认删除该菜谱吗, 警告, { type: warning }) .then(async () { await deleteRecipe(row.id); ElMessage.success(删除成功); loadData(); // 重新加载列表 }) .catch(() {}); }; const handleView (row) { currentRecipe.value row; dialogVisible.value true; }; onMounted(() { loadData(); }); /script2. 文件导出功能实现毕业设计常要求将数据导出为PDF或Excel。这里以前后端分离详情导出pdf实现步骤为例简述思路后端提供一个API端点如/api/recipes/{id}/export-pdf/接收菜谱ID。使用像ReportLab或WeasyPrint这样的Python PDF库根据菜谱数据生成PDF文件然后返回文件流或一个临时下载链接。前端在管理后台的“操作”列添加一个“导出PDF”按钮。点击后调用上述API。由于API返回的是文件流前端可以通过创建隐藏的a标签并设置download属性或者使用window.open(url)的方式来触发浏览器下载。// 前端调用示例 const exportPdf (recipeId) { const token localStorage.getItem(token); const url /api/recipes/${recipeId}/export-pdf/; const link document.createElement(a); link.href url; link.setAttribute(download, recipe_${recipeId}.pdf); link.style.display none; document.body.appendChild(link); link.click(); document.body.removeChild(link); };5. 项目部署与毕业设计材料整合项目开发完成最后一步是让它跑起来并整理成合格的毕业设计材料。5.1 后端部署以Linux服务器为例环境准备在服务器上安装Python、MySQL、Nginx、Supervisor。项目上传与依赖安装# 克隆项目或上传代码 cd /var/www/ git clone your-project.git cd family-chef-backend # 创建虚拟环境并激活 python3 -m venv venv source venv/bin/activate # 安装依赖 pip install -r requirements.txt数据库配置在MySQL中创建数据库修改Django的settings.py中的DATABASES配置然后执行迁移。python manage.py makemigrations python manage.py migrate python manage.py createsuperuser # 创建管理员收集静态文件如果使用了Django的静态文件需要收集。python manage.py collectstatic使用Gunicorn运行DjangoGunicorn是一个WSGI HTTP服务器。pip install gunicorn gunicorn --workers 3 --bind 0.0.0.0:8000 your_project.wsgi:application使用Supervisor管理进程让Gunicorn在后台稳定运行并开机自启。创建配置文件/etc/supervisor/conf.d/family-chef.conf。[program:family-chef] command/var/www/family-chef-backend/venv/bin/gunicorn --workers 3 --bind 0.0.0.0:8000 your_project.wsgi:application directory/var/www/family-chef-backend userwww-data autostarttrue autorestarttrue redirect_stderrtrue stdout_logfile/var/log/supervisor/family-chef.log然后更新Supervisorsudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start family-chef。配置Nginx反向代理让Nginx处理静态文件并将动态请求转发给Gunicorn。配置/etc/nginx/sites-available/family-chef。server { listen 80; server_name your-api-domain.com; # 你的API域名 location /static/ { alias /var/www/family-chef-backend/static/; # Django静态文件目录 } location /media/ { # 如果你有用户上传的媒体文件 alias /var/www/family-chef-backend/media/; } location / { proxy_pass http://127.0.0.1:8000; # 转发给Gunicorn proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }启用配置并重启Nginxsudo ln -s /etc/nginx/sites-available/family-chef /etc/nginx/sites-enabled/sudo nginx -t sudo systemctl restart nginx。5.2 前端部署微信小程序直接在微信开发者工具中上传代码提交审核即可。Vue管理后台运行npm run build生成dist静态文件。可以将dist目录整个上传到服务器用Nginx配置一个静态网站来访问或者使用Netlify、Vercel等静态站点托管平台部署非常方便。5.3 毕业设计材料打包这是体现你项目完整性和专业性的关键。一个标准的毕业设计材料包应该包含源代码包含完整的Django后端、微信小程序前端、Vue管理后台前端三个目录。确保.gitignore文件正确没有包含敏感信息如settings.py中的密钥应使用环境变量但可以提供一个settings.example.py。数据库脚本database_schema.sql纯SQL文件包含所有建表语句。可以通过python manage.py sqlmigrate app_name migration_number命令生成或者用MySQL的mysqldump -d导出结构。sample_data.sql可选的示例数据插入脚本方便答辩时演示。毕业论文这是重头戏。论文结构应包含摘要、绪论背景与意义、相关技术介绍对微信小程序、Django、Vue、MySQL等技术进行分析、系统分析与设计需求分析、功能模块、数据库设计、系统实现详细阐述关键模块的实现配核心代码截图、系统测试、总结与展望。切忌直接贴大段代码用流程图、类图、序列图和关键代码片段来说明问题。你的项目实现过程就是论文最好的素材。部署文档一个清晰的DEPLOYMENT.md文件写明从零开始部署整个系统所需的步骤、命令和配置。这能极大提升项目的可复现性。视频教程/演示录像录制一个10-15分钟的视频涵盖系统主要功能演示小程序端和管理后台、关键代码讲解、部署流程简介。这是答辩时的加分项能让老师快速了解你的工作。最后的叮嘱做毕业设计技术实现固然重要但清晰的文档、完整的材料、流畅的演示同样关键。这个“家庭大厨”项目从技术选型到最终打包提供了一条被验证过的路径。希望这份超详细的拆解能帮你不仅做出一个能跑的项目更能交出一份让自己和导师都满意的毕业答卷。过程中遇到的具体问题比如微信登录的细节、Django REST framework更复杂的序列化、Vue路由的权限控制都可以在这个坚实的基础上继续深入探索。本文还有配套的精品资源点击获取
返回列表