新闻详情

新闻详情

首页 / 资讯中心 / 详情

Django+微信小程序返校疫情管理系统开发全解析

发布时间:2026/10/2 10:34:37来源:尧图网络
Django+微信小程序返校疫情管理系统开发全解析
我前前后后帮人看过不少毕业设计项目djangopython微信小程序的大学学生返校疫情管理系统这个题目几乎年年有人选。原因也很简单它是一个足够典型的全栈业务系统——后端要处理用户、打卡记录、返校申请、审批流这些实体关系前端要搞定小程序端的登录态、页面跳转、列表加载、表单提交论文里还有用例图、E-R图、时序图可以画工作量可控、逻辑清晰、演示效果好。但正因为选的人多老师的要求也跟着水涨船高光把功能堆出来已经不够得在架构设计、接口规范、数据一致性这些地方拿出点真东西。这篇文章把我实际做这个项目的思路、核心代码、踩过的坑全部整理出来。涉及的技术栈就是标题里的三样Python 3 Django 3.2/4.x 做后端 API微信小程序做前端展示和交互再加 MySQL 存数据。我会尽量按“从需求到实现、从前端到后端、从开发到答辩”的顺序讲适合正在做同类毕设的人直接参考也适合想系统了解这个技术组合的读者。1. 项目立项前的需求梳理与技术选型1.1 这个系统到底要解决什么问题先别急着写代码把业务需求拆清楚比什么都重要。返校疫情管理系统的核心场景是三段式学生在离校期间每日上报健康状态、辅导员和学院管理员审核返校申请、返校后持续跟踪在校健康情况。对应到功能模块至少得有这些学生端每日健康打卡、返校申请填写、申请进度查看、个人打卡记录查询教师/辅导员端查看所带学生的打卡情况、审核返校申请、导出汇总表管理员端用户管理学生、教师、学院、全校打卡统计、返校审批配置、公告发布公共模块微信授权登录、消息通知申请通过/驳回、数据看板很多同学上来就画了二十多个表把系统设计得极其庞大结果实现到一半发现时间根本不够。我的建议是第一版先做主线也就是“打卡 申请 审批 统计”这一条链路延展功能放到论文的“系统展望”里写答辩时再说。毕业设计最重要的是完整性和逻辑自洽不是功能数量。1.2 为什么选Django微信小程序这套组合这个组合在当时的调研阶段就是奔着“开发效率最高、演示门槛最低”去的。先说 Django。它是 Python 生态里最适合快速搭业务系统的框架自带 Admin 后台、ORM、认证体系、CSRF 防护。做这种管理型系统Django 的 Model-View-Template 思想天然契合尤其适合学生党——因为你不需要像用 Spring Boot 那样配一堆 Bean也不用像写 Flask 那样自己拼 SQLAlchemy 的零碎组件。Django 的 ORM 可以直接用 Python 语法操作数据库省掉了手写 SQL 的负担这在赶论文的时候非常救命。再说微信小程序。选它不是因为微信生态多先进而是因为“用户触达”简单。学生不需要下载 App微信扫一扫就能用对于毕业设计演示来说这个体验比做 Web 端或者 Android 端都要好。而且小程序的原生框架就是 JS WXML WXSS会一点前端基础就能上手。技术选型对比过几轮方案后端前端适合场景学习成本Django 小程序Python/Django微信原生业务系统、毕设首选中低Spring Boot 小程序Java/Spring微信原生企业级实习背景高Flask 小程序Python/Flask微信原生轻量接口服务低但缺脚手架Django VuePython/DjangoWeb纯 PC 端管理中我最终定下来 Django 微信原生小程序还有一个重要原因是 Djangorestframework 可以直接生成符合 RESTful 规范的 API。小程序端通过 wx.request 发起请求配合 token 做身份认证整个数据通道非常清晰论文里的架构图也好画。2. Django后端框架搭建与核心模型设计2.1 项目初始化和目录规划后端我用的是 Django 3.2 LTS当时最新的稳定版其实 4.x 也完全没问题区别不大。建议直接从虚拟环境开始mkdir school-epidemic-system cd school-epidemic-system python -m venv venv # Windows: venv\Scripts\activate Mac/Linux: source venv/bin/activate pip install django3.2.18 djangorestframework django-cors-headers pillow django-admin startproject config . python manage.py startapp users python manage.py startapp health python manage.py startapp apply我把项目命名为 config而不是默认的 manage.py 所在的目录名是为了避免和具体业务模块混淆。三个 app 各管一摊users用户管理包括学生、教师、管理员三种角色也处理微信登录的 openid 绑定health每日打卡、健康信息、统计apply返校申请、审批流程、审批记录这个划分从领域模型出发比单个 app 写完所有东西要清晰得多。论文里的模块设计这一章画三个模块的包图就够了。2.2 数据模型设计用户、打卡记录、返校申请、审批流Django 的模型是 ORM 的核心调整成本越早越低。以下是关键模型的设计思路users中的用户模型from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): ROLE_CHOICES ( (student, 学生), (teacher, 教师), (admin, 管理员), ) role models.CharField(max_length10, choicesROLE_CHOICES, defaultstudent) student_id models.CharField(max_length20, blankTrue, nullTrue) college models.CharField(max_length50, blankTrue) phone models.CharField(max_length11, blankTrue) wx_openid models.CharField(max_length50, blankTrue, nullTrue, db_indexTrue) class Meta: db_table sys_user这里有个细节Django 自带的 User 模型直接用继承扩展比新建一个 UserProfile 一对一表更方便。原因很简单——登录、权限、session 这些都用框架内置能力不受影响。改表名是为了和项目逻辑中的“学生/教师”语义对应避免误用默认的auth_user。health中的打卡模型class HealthCheck(models.Model): user models.ForeignKey(User, on_deletemodels.CASCADE, related_namehealth_checks) date models.DateField() temperature models.DecimalField(max_digits4, decimal_places2) is_fever models.BooleanField(defaultFalse) is_contact_risk models.BooleanField(defaultFalse) location models.CharField(max_length100, blankTrue) remark models.TextField(blankTrue) created_at models.DateTimeField(auto_now_addTrue) class Meta: db_table health_check unique_together (user, date)这里最大的坑是unique_together。每日打卡必须保证同一用户同一天只能有一条记录如果不用联合唯一约束就要在接口层加锁或者先查再插并发下很容易出现重复打卡。我实际测试过两个请求同时进来先查后插大概率能触发唯一约束冲突正确做法是用get_or_create或者捕获IntegrityError。apply中的返校申请模型class ReturnApply(models.Model): STATUS_CHOICES ( (pending, 待审核), (approved, 已通过), (rejected, 已驳回), (cancelled, 已撤销), ) user models.ForeignKey(User, on_deletemodels.CASCADE, related_namereturn_applies) apply_date models.DateField(auto_now_addTrue) return_date models.DateField() transport models.CharField(max_length20) start_city models.CharField(max_length50) end_city models.CharField(max_length50) health_code models.CharField(max_length20) status models.CharField(max_length10, choicesSTATUS_CHOICES, defaultpending) review_comment models.TextField(blankTrue) created_at models.DateTimeField(auto_now_addTrue) class Meta: db_table return_apply审批记录我用一个独立的ReviewLog模型来存这样后面论文里画“审批时序图”和“数据流图”都有据可查。很多人只在申请单上改状态一旦要查某个审批人什么时候审的、批了什么就完全没记录答辩时被问住很难受class ReviewLog(models.Model): apply models.ForeignKey(ReturnApply, on_deletemodels.CASCADE, related_namelogs) reviewer models.ForeignKey(User, on_deletemodels.CASCADE) action models.CharField(max_length10) # approve/reject comment models.TextField(blankTrue) created_at models.DateTimeField(auto_now_addTrue) class Meta: db_table review_log2.3 查询、更新与删除对象的正确姿势热搜词里有一条是“django执行查询-删除对象”这确实是新手最容易搞混的地方。Django 的删除分两层模型实例的delete()方法和 QuerySet 的delete()方法前者只删一条后者批量删除并返回删除数量。# 删除单条打卡记录 check HealthCheck.objects.get(id1) check.delete() # 批量删除某个学生的所有打卡 HealthCheck.objects.filter(user_id1).delete()做业务系统时要特别注意“物理删除”和“逻辑删除”的选择。比如返校申请被学生撤销如果直接物理删除审批记录就没了数据审计功能就瞎了。我的做法是给核心业务表都加上is_active或status字段前端“撤销”按钮其实是把状态改成cancelled而不是真正从库里删掉# 撤销申请伪删除保留数据 ReturnApply.objects.filter(idapply_id, userrequest.user).update(statuscancelled)update()方法走的是 QuerySet 批量更新不会触发模型的 save() 方法性能更好但如果你依赖信号或 save 钩子做额外逻辑就得注意了。我建议核心业务用 save() 加状态判断统计类的批量更新用 update()既清晰又高效。3. 接口层设计与小程序前端的请求联动3.1 基于Token的认证与权限隔离Django 后端不是给浏览器直接渲染页面的而是提供 JSON 接口给小程序调用。这里我用的是djangorestframework-simplejwt做 JWT 认证理由是无状态、小程序端好保存不用像 session 那样处理 cookie。安装和配置# settings.py INSTALLED_APPS [ ... rest_framework, rest_framework_simplejwt, ] REST_FRAMEWORK { DEFAULT_AUTHENTICATION_CLASSES: [ rest_framework_simplejwt.authentication.JWTAuthentication, ], DEFAULT_PERMISSION_CLASSES: [ rest_framework.permissions.IsAuthenticated, ], } # 可以通过自定义 serializer 把 User 的自定义字段写进 token from rest_framework_simplejwt.serializers import TokenObtainPairSerializer class CustomTokenObtainPairSerializer(TokenObtainPairSerializer): classmethod def get_token(cls, user): token super().get_token(user) token[role] user.role token[student_id] user.student_id return token小程序端登录流程是这样先用wx.login拿到 code发给后端后端拿 code 调微信接口换 openid再判断用户是否已绑定。已绑定就直接返回 token未绑定就让用户填学号姓名绑定后返回 token。这里有个实操细节微信小程序登录返回的 code 有效期只有五分钟而且只能用一次。我当时调试的时候反复报40029错误排查了半天才发现是后端code缓存了第二次请求用的还是同一个 code。正确做法是每次进入小程序都重新wx.login拿新鲜 code不要存着复用。3.2 小程序端网络请求封装与列表加载小程序原生wx.request用起来还行但每个页面都重复写 header、baseURL、错误处理就太难受了。我参考了网上常见的封装思路写了一个request.jsconst BASE_URL http://127.0.0.1:8000/api; function request(url, method GET, data {}) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL url, method: method, data: data, header: { Content-Type: application/json, Authorization: Bearer wx.getStorageSync(token) }, success(res) { if (res.statusCode 200) { resolve(res.data); } else if (res.statusCode 401) { wx.navigateTo({ url: /pages/login/login }); reject(res); } else { wx.showToast({ title: res.data.message || 请求失败, icon: none }); reject(res); } }, fail(err) { wx.showToast({ title: 网络异常, icon: none }); reject(err); } }); }); } module.exports { request, BASE_URL };列表页用到了热搜词里的“页面列表加载更多”这是小程序很常见的需求。我的方案是分页参数page/pageSize 触底事件Page({ data: { list: [], page: 1, pageSize: 10, hasMore: true }, onReachBottom() { if (!this.data.hasMore) return; this.loadMore(); }, async loadMore() { const res await request(/health/records/?page this.data.page, GET); const newList this.data.list.concat(res.results); this.setData({ list: newList, page: this.data.page 1, hasMore: res.next ! null }); } })一个隐蔽的 bugonReachBottom触底后请求没结束又下拉触底会连续发多个请求。我加了一个isLoading标志位解决if (this.data.isLoading) return; this.setData({ isLoading: true }); // ... 请求结束 finally 置回 false3.3 抓包与联调中的常见坑在做毕设的时候小程序真机预览和本地联调经常遇到“请求不到数据”的问题。很多同学在这里卡死我的经验是三部走第一步看控制台报错。用微信开发者工具打开“不校验合法域名”选项本地 Django 开发服务器127.0.0.1:8000才能被访问到。第二步如果真机调试连不上本地直接把 Django 服务器跑在局域网 IP 上比如python manage.py runserver 0.0.0.0:8000手机和电脑连同一个 WiFiBASE_URL 写成http://192.168.x.x:8000。这里注意 Windows 防火墙会拦截入站请求我第一次就栽在这上面。第三步用抓包工具Charles 或 Fiddler看请求头和响应体。我见过好几个人后端接口明明返回了数据小程序却显示空列表一抓包才发现是 JSON 里字段名对不上——后端返回student_id前端取的是studentId。联调时先抓包确认字段再改代码效率成倍提升。4. 核心功能模块的落地实现4.1 每日健康打卡模块打卡模块是系统的“日常主功能”学生每天进入小程序先看今天是否已打卡再填写体温、是否发热、是否接触风险人群。后端接口设计如下# urls.py path(health/check/, HealthCheckView.as_view(), namehealth-check), # views.py class HealthCheckView(APIView): def get(self, request): today timezone.localdate() check, created HealthCheck.objects.get_or_create( userrequest.user, datetoday, defaults{temperature: 36.5} ) return Response(serializer.data) def post(self, request): user request.user today timezone.localdate() if HealthCheck.objects.filter(useruser, datetoday).exists(): return Response({message: 今日已打卡}, status400) serializer HealthCheckSerializer(datarequest.data) if serializer.is_valid(): serializer.save(useruser, datetoday) return Response(serializer.data, status201) return Response(serializer.errors, status400)注意get_or_create在 GET 接口里的使用如果今天没打卡系统自动生成一条空记录前端可以拿这条记录去做表单填充。这样设计有个好处前端不用额外判断“今天是新的一天”直接覆盖显示即可。我还给打卡列表接口加了日期过滤和导出功能。导出用的是csv标准库生成文件流后返回给前端保存# 导出 CSV import csv from django.http import HttpResponse def export_health(request): response HttpResponse(content_typetext/csv; charsetutf-8-sig) response[Content-Disposition] attachment; filenamehealth.csv writer csv.writer(response) writer.writerow([姓名, 学号, 日期, 体温, 是否发热]) ...这里charsetutf-8-sig是给 Excel 看的不加这个中文会乱码。4.2 返校申请与审批流程返校申请流程是核心业务闭环学生提交→教师审批→可选学院管理员二次审批→学生看到结果。状态机我用一个字典维护保证流程可扩展ALLOWED_TRANSITIONS { pending: [approved, rejected, cancelled], approved: [cancelled], rejected: [pending], # 驳回到待审状态允许学生修改后重新提交 } def change_status(apply, new_status): if new_status not in ALLOWED_TRANSITIONS.get(apply.status, []): raise ValidationError(非法的状态转换: %s - %s % (apply.status, new_status)) apply.status new_status apply.save()这个设计在答辩时加分很多因为评委很容易问“如果老师错点通过了怎么办”我们允许已通过的申请被学生撤销驳回的申请可以重新提交这些边界情况都照顾到了。教师审批接口要做两件事更新申请状态、写审批日志。必须放在一个事务里from django.db import transaction transaction.atomic def review_apply(request, apply_id): apply ReturnApply.objects.get(idapply_id) action request.data.get(action) comment request.data.get(comment, ) if action approve: change_status(apply, approved) elif action reject: change_status(apply, rejected) ReviewLog.objects.create( applyapply, reviewerrequest.user, actionaction, commentcomment ) return Response({message: 操作成功})事务保证了申请状态和日志的一致不会出现状态变了但没记录、或者记录写了但状态没变的尴尬情况。这个虽然是小细节但答辩时提一句“我用了事务保证数据一致性”比吹十句框架厉害都管用。4.3 数据统计与可视化概览统计模块是管理员的“面子工程”做得好直接给论文和答辩视频加分。我做了一个总览页包括全校某日打卡率、近七日体温趋势、各学院申请通过率。统计接口直接聚合查询from django.db.models import Count, Q from django.db.models.functions import TruncDate today timezone.localdate() total_students User.objects.filter(rolestudent).count() checked_today HealthCheck.objects.filter(datetoday).count() rate round(checked_today / total_students * 100, 2) if total_students else 0小程序端用 ECharts 的ec-canvas组件画折线图和柱状图。这一块需要注意的是小程序 canvas 组件的宽高用 rpx 适配容易出问题最好用wx.getSystemInfoSync()动态计算像素宽度。我踩过这个坑默认 100% 宽度的 canvas 在真机上会挤压变形改成固定 px 宽度后正常了。指标设计上我的经验是不要一次性展示十几个统计项选三四个最重要的讲清楚即可。打卡率、异常人数、申请审批通过率、每日趋势这四个基本能覆盖论文“系统功能展示”的需求。5. 部署、测试与毕业论文素材沉淀5.1 本地调试到服务器部署毕设演示一般有两种方式本地跑给评委看或者部署到服务器远程访问。我建议两条腿走路电脑开本地服务器也放一份现场切换。部署我用的是最经典的组合Nginx Gunicorn MySQL。大体流程# 服务器上 pip install gunicorn gunicorn config.wsgi:application -b 127.0.0.1:8000 --workers3 # Nginx 配置反向代理这里有个点容易被忽略Django 的DEBUG False之后静态文件不会自动服务如果你用到了 Django Admin 后台需要python manage.py collectstatic把静态文件收集到STATIC_ROOT否则后台页面 CSS 全丢。腾讯云服务器配合备案域名是最常见的选择注意小程序要配置 request 合法域名必须是 HTTPS。如果你只想在局域网演示直接runserver 0.0.0.0:8000就行不用折腾 Nginx。5.2 测试数据准备与论文图表素材论文通常需要大量截图所以我特意准备了一套“看上去很真实”的测试数据脚本用 Django Fixture 或者自定义 command 生成三十个学生、三周打卡记录、几十条申请审批记录。python manage.py shell generate_data.py脚本核心逻辑很简单遍历学生、遍历日期范围、随机生成体温和打卡状态import random, datetime from users.models import User from health.models import HealthCheck students User.objects.filter(rolestudent) start datetime.date.today() - datetime.timedelta(days21) for stu in students: for i in range(21): day start datetime.timedelta(daysi) HealthCheck.objects.create( userstu, dateday, temperatureround(random.uniform(36.2, 36.8), 2), is_feverFalse, is_contact_riskFalse )测试数据的“真”不在数量而在合理性。体温全部在 36.5 附近反而不真实按正态分布稍微浮动一点偶尔插入一两条异常记录图表看起来才像话。5.3 答辩演示注意事项答辩演示的时间一般只有五到十分钟我的经验是提前彩排三遍重点练三个环节学生登录打卡的流畅操作、教师审批一条申请的完整流程、管理员看统计数据的切换速度。还有个小技巧把数据库里测试学生的密码写死在登录页面旁边演示时不要现找手机扫码登录。小程序用微信登录在电脑演示会遇到扫码等待的尴尬我建议在系统里留一个“账号快捷登录”入口输入测试账号直接进系统演示节奏会顺很多。6. 踩坑实录与经验总结6.1 十个典型开发问题速查表这里整理了我整个开发周期里遇到的高频问题按后端、前端、联调分类问题现象根本原因解决办法小程序请求报 403Django 的 CSRF 校验拦截了非浏览器请求在REST_FRAMEWORK中关闭默认 CSRF改用 JWT 认证本地能访问手机连不上防火墙拦截或未监听 0.0.0.0runserver 0.0.0.0:8000关闭防火墙或加放行规则中文写入 MySQL 乱码数据库字符集不是 utf8mb4建库时指定CHARACTER SET utf8mb4列表加载时重复请求触底事件在请求途中再次触发用isLoading标志位做防抖token 过期不提示请求 401 未统一处理封装 request401 时跳登录页并清理本地缓存删除外键数据报错外键约束on_deletemodels.PROTECT根据业务改成CASCADE或先处理关联数据日期过滤失效前端传的是字符串Django 比较时带时区差异后端统一用date__range配合datetime.date类型Admin 后台样式丢失DEBUGFalse 时未收集静态文件执行collectstatic配置STATIC_ROOT微信登录 code 失效code 只能用一次被缓存复用了每次登录重新wx.login()定时任务没跑起来开发环境没启动 celery/scheduler用django-crontab或接入系统 cron这些坑都是论文致谢和总结里最好的素材把它们写进“系统测试与问题分析”章节比放十张代码截图更有说服力。6.2 关于毕业设计的一些个人经验最后说点实在话。做这个项目表面上是技术开发实际上是对“需求到实现”完整流程的训练。我见过太多人把精力花在纠结“用什么技术栈”而不是“怎么设计业务逻辑”上结果论文改了七八稿评委一问场景细节就卡壳。我个人最大的体会是先画好状态图和流程图再写代码。返校申请的状态流转、打卡的重复约束、审批的事务边界这些用流程图和状态机表达出来代码实现只是翻译工作。软件开发里最值钱的不是说你会几个框架而是能把模糊的业务需求拆成可执行的功能点这也是毕业设计真正想训练你的东西。如果你正在写这篇论文或者正在做这个系统建议你从今天开始建一个“坑记录”文档每遇到一个问题就记一笔等写到“问题与对策”那一章时你会发现根本不用编素材全是实打实的干货。祝顺利答辩。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

S32DS_V2018.R1 Win10兼容性问题与离线激活实战指南 2026/10/2 11:29:49

S32DS_V2018.R1 Win10兼容性问题与离线激活实战指南

1. 为什么S32DS_ARM_V2018.R1在Win10上安装会“卡在License界面”——一个被忽略的系统兼容性真相 你不是第一个,也绝不会是最后一个,在Win10上点开S32DS_ARM_V2018.R1安装包后,盯着那个灰底白字的License Activation窗口发呆的人。光标在“E…

阅读更多 →
PICO空间计算上手:从零搭建MR场景,人人都是开发者 2026/10/2 11:29:49

PICO空间计算上手:从零搭建MR场景,人人都是开发者

第一次把PICO头显戴到头上的时候,我心里其实是有点抗拒的。这类设备我体验过不少,展会上排队五分钟,戴上去转两圈,晕得走路都飘。但那次不一样。我面前的茶几上被“放”了一盏虚拟台灯,光晕会随着我弯腰的角度实时变化…

阅读更多 →
MoE推理加速:W4A8量化与MMAC协同优化实战 2026/10/2 11:29:49

MoE推理加速:W4A8量化与MMAC协同优化实战

1. 为什么 W4A8 是当下 MoE 推理的甜点区 1.1 从一次显存告急说起 上个月帮朋友看一个 MoE 模型的部署问题,他手里只有一张 24G 显存的卡,想把一个总参数量接近千亿级别的 MoE 模型跑起来做推理。第一反应肯定是塞不进去,光权重按 FP16 算就…

阅读更多 →
论文被吐槽逻辑乱?导师强推这几个AI论文软件 2026/10/2 11:29:49

论文被吐槽逻辑乱?导师强推这几个AI论文软件

想写论文又快又好,关键是用对 AI 工具、走对流程——资深教授普遍推荐:千笔AI(中文全流程首选) 豆包学术版(轻量高效) DeepSeek 学术版(理工 / 长文本) Grammarly Academic&#xff…

阅读更多 →
从零手把手DIY一台OpenRig开放式硬件测试平台 2026/10/2 11:29:49

从零手把手DIY一台OpenRig开放式硬件测试平台

1. OpenRig到底是什么,我为什么折腾了这么一台"裸架" OpenRig往简单里说,就是一台开放式PC硬件测试平台——没有侧板、没有传统机箱结构,主板直接平放或者竖挂在铝合金框架上,电源、显卡、散热器全部露天安装。听起来像…

阅读更多 →
从零手搓AI工程化流程:数据、训练、评估与部署全链路实践 2026/10/2 11:29:42

从零手搓AI工程化流程:数据、训练、评估与部署全链路实践

1. 为什么我要从零手搓一套AI工程化流程第一次看到ai-engineering-from-scratch这个项目名的时候,我正被一堆散落在各处的实验脚本折磨得够呛。Jupyter Notebook 里躺着十几个版本的模型训练代码,文件名从train_final.py一路排到train_final_v3_really_f…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉