拓冰建站拓冰建站
首页 / 资讯中心 / 正文

基于Python和Vue3的校园学科竞赛管理系统开发实践

简介面向高校教育信息化与学科竞赛管理场景的一份完整毕业设计文档采用PythonDjangoVueMySQL技术栈基于B/S三层架构实现竞赛信息的即时发布、规范化报名、成绩统计与排名等核心功能适合计算机相关专业学生借鉴系统设计与论文写作思路。文档详细覆盖学生模块、竞赛信息模块、报名竞赛模块、成绩排名模块及管理员审核流程并对系统架构、数据库设计与实现方案进行了系统阐述内容预览中还包含中英文摘要、关键词及完整论文结构便于快速了解整体框架与关键技术细节。压缩包内为1个doc文件整体大小约15.93MB已有50人学习下载。对正在筹备竞赛管理类课题或需要参考Django与Vue前后端整合方案的研究者而言是一份结构清晰、可直接用于论文撰写与项目起步的实用资料。 写这个管理系统的时候我其实已经用光了本科四年攒下的所有“动手能力”。从最初只想在论文里画几张用例图糊弄过去到后来认认真真把前后端拆开、部署上线、跑完整个报名评分流程三个月过去我对“校园学科竞赛管理系统”这九个字的理解完全不一样了。这篇不聊那些从需求分析抄到验收标准的套话只讲我实际怎么做、为什么这么选、以及联调阶段真实踩过的坑给准备用 Python 和 Vue3 做类似管理系统的同学一条可以复现的路。1. 竞赛管理平台需求痛点和系统定位1.1 手工作坊式办赛的三大痛点很多学校现在的学科竞赛管理还停留在“辅导员发Excel表、学生填完发回来、老师再手工汇总”的阶段。表面看能跑通实操过就知道有多折磨报名信息格式五花八门有的学生把手机号写成“188-xxxx-xxxx”有的把组员名单直接塞在备注里评委打分靠纸质打分表统计的时候得一个人对着计算器按半天最头疼的是多轮比赛的状态追踪复赛名单、决赛时间、获奖公示全靠群消息通知漏一个学生就是事故。所以这个系统的第一个核心定位就是把报名、审核、比赛进程、评分、成绩公布这条链条搬到线上让每个环节都有据可查、有迹可循。1.2 系统边界管理端、教师端、学生端三端划分需求梳理阶段我做了很多轮减法。最开始也想过做移动端小程序、加消息推送、做在线答辩视频模块后来全部砍掉了。毕设系统最重要的是逻辑闭环而不是功能堆砌。我最终保留的是三个明确的角色域学生端查看竞赛公告、在线报名、提交作品、查看个人成绩和获奖信息教师端评委对分配到的作品打分、填写评语、查看自己参与评审的竞赛列表管理端管理员发布竞赛、审核报名、分配评委、管理作品、录入/审核成绩、发布获奖公示三端共用同一套用户体系后端通过角色字段控制接口权限。这样设计的好处是权限模型简单清晰论文里好画图答辩时好讲代码实现也省事——不需要引入复杂的 RBAC 框架一个中间件判断角色就够了。1.3 系统用例与核心流程整个系统的核心流程可以压缩成一句话管理员发布竞赛 - 学生报名 - 管理员审核报名 - 学生提交作品 - 管理员分配评委 - 评委打分 - 系统自动计算均分 - 管理员发布成绩和获奖名单。这条主链路决定了数据库的四张核心业务表——竞赛表、报名表、作品表、评分表。所有的设计决策包括字段命名、外键关系、接口粒度都是围绕这条链路展开的。我建议所有准备做类似系统的同学动手写代码之前先把这条链路捋清楚它比任何需求文档都好用。2. 技术选型背后Python、Vue3 与毕设场景的匹配2.1 为什么后端用 Python 而不是 Java后端选 Python 并不是因为它比 Java“好”而是因为它更适合这个项目的体量和开发节奏。Django 框架自带 Admin 后台我开发初期几乎没写一行后台管理代码就靠 Admin 快速录入了测试数据这让前期的功能验证变得极其高效。等核心业务接口写完Admin 后台还能作为管理端的一个“保底方案”——即使前端页面没做完也不影响演示核心流程。另一个现实理由是答辩环境的不确定性。用 Python 写的后端在答辩现场的笔记本上重新跑起来的成本远低于 Java 工程。装好 Python 环境、pip 装上依赖、跑一次迁移脚本几分钟就能起服务。Java 那套 JDK 版本、Maven 依赖、配置文件的连锁问题在演示当天任何一个环节出错都足够让人崩溃。2.2 为什么前端选 Vue3 而不是 ReactVue3 在毕设场景下的优势体现在三个方面。第一是学习曲线平缓Composition API 的写法比 React 的 Hooks 规则更直观没有闭包陷阱、依赖数组这些容易让新手懵的概念。第二是中文生态极其友好Element Plus 组件库的中文文档、各类超详细教程到处都是遇到问题几乎都能搜到现成答案。第三是和 Vite 搭配的开发体验非常舒服热更新速度快改完代码浏览器立刻生效这在赶工期的阶段是实打实的效率提升。Vue3 里我大量使用了组合式函数来封装可复用的逻辑。比如一个usePagination组合式函数把分页的当前页、每页条数、总数、加载方法封装在一起列表页只需要调用一次就能少写一大段重复代码。这在写论文的技术章节时也是一个亮点——“通过 Composition API 实现逻辑复用”比干巴巴地写“使用了 Vue3 框架”有说服力得多。2.3 项目结构前后端分离后的目录设计前后端分离是我从一开始就定下的架构。项目分了两个独立的目录互不干扰backend/ manage.py config/ # 项目配置 apps/ users/ # 用户模块 competitions/ # 竞赛模块 registrations/ # 报名模块 works/ # 作品模块 scores/ # 评分模块 announcements/ # 公告模块 requirements.txt frontend/ src/ api/ # axios 接口封装 assets/ components/ # 通用组件 router/ stores/ # pinia 状态管理 views/ admin/ teacher/ student/ utils/这个结构的好处是后端按业务模块拆 app前端按角色分目录论文里的系统架构图画出来一目了然代码也容易找。前端我用 Pinia 做了全局状态管理主要存用户登录信息和角色路由守卫根据角色控制页面访问权限。导航菜单也是动态渲染的——不同角色登录后看到的菜单项完全不同。3. 系统数据建模与接口设计稳定性的地基3.1 数据库表设计与关系拆解数据库设计是整个系统我最重视的部分。表设计不合理后面写多少代码都别扭。我用了 MySQL核心表一共八张这里列一下主题结构表名核心字段说明usersusername, password, role, real_name, student_no统一用户表role 区分学生/教师/管理员competitionstitle, description, category, start_time, end_time, status竞赛公告status 控制报名/进行/结束registrationsuser, competition, team_name, members, status报名记录status 为待审核/通过/驳回worksregistration, title, file, submit_time作品表一个报名记录对应一份作品scoreswork, judge, score, comment评分表一个作品对应多条评分awardscompetition, registration, rank获奖表发布公示时生成announcementstitle, content, publish_time系统公告competition_judgescompetition, judge竞赛和评委的多对多关系用户表我把三种角色放在一张表里用 role 字段区分而不是拆成学生表、教师表。因为三种角色有大量公共字段姓名、账号、联系方式拆表会导致登录和权限判断变得异常复杂。对于这个体量的系统“单用户表 角色字段”是最务实的选择。3.2 权限模型用 Django 的 Group 还是自建 RoleDjango 自带 Group 和 Permission理论上可以用它们实现权限控制。但我实践后放弃了原因只有一个写论文的时候解释“如何使用 Django 内置 RBAC”远比解释“自己实现了一个基于角色的访问控制”要费劲而且内置权限的数据结构对评委这个角色并不友好——一个评委只能给“分配给他”的竞赛打分这种资源级权限是 Group 权限解决不了的。我最终的做法是基础权限用role字段 装饰器判断资源级权限比如评委只能看到自己负责的竞赛在视图层手动过滤。听起来简单但实际效果非常好。每次请求进来先通过中间件解析 JWT 拿到用户 ID 和角色然后视图里根据角色做数据过滤。逻辑直白排查问题也方便。3.3 API 风格与状态码约定接口我用 RESTful 风格基于 Django REST Framework 实现。路径设计遵循资源嵌套原则POST /api/auth/login/ 登录 GET /api/competitions/ 竞赛列表 POST /api/competitions/ 管理员创建竞赛 POST /api/competitions/{id}/register/ 学生报名 GET /api/competitions/{id}/registrations/ 查看某竞赛的报名列表 POST /api/works/ 提交作品 POST /api/works/{id}/score/ 评委打分 GET /api/competitions/{id}/results/ 查看成绩状态码约定也提前定好200 成功、201 创建成功、400 参数错误、401 未登录、403 无权限、404 资源不存在。前端 Axios 拦截器统一处理遇到 401 就清除登录状态跳回登录页。这些约定看起来基础但如果没有提前定清楚前后端联调阶段光是字段名和错误码就能撕扯一周。4. 核心功能落地报名、审核、评分、统计的实现细节4.1 竞赛发布与报名日期校验和名额控制的常见坑竞赛发布时最容易出问题的是时间字段的处理。前端传的是“2024-05-20 10:00:00”这种格式后端 Django 的 DateTimeField 能自动解析但有一个坑前端如果传带T的 ISO 字符串比如2024-05-20T10:00:00DRF 也能解析但存进数据库后前端再读出来时格式可能变成带T和时区的导致页面显示不统一。我最后的处理方案是后端统一使用 Django 的USE_TZ False关闭时区转换存 Naive DateTime前端在 API 层统一封装日期格式化函数展示时按YYYY-MM-DD HH:mm:ss格式输出。别小看这个统一系统的报名、比赛、公示三个环节全依赖时间判断时间格式不一致会引发连锁 bug。名额控制也是实际场景里必须考虑的问题。每个竞赛可以设置最大报名人数报名接口里用select_for_update()加上行级锁先查当前人数再判断是否允许报名避免高并发下超员。毕设环境不会有真实并发压力但写这个处理逻辑在论文里是一个明确的技术亮点。4.2 作品提交文件上传与格式校验作品提交是多媒体文件上传我用 Django 的FileField存文件路径前端用FormData提交Axios 不手动设置 Content-Type让浏览器自动生成带 boundary 的 multipart 格式。上传格式校验分两层前端选文件时通过accept属性限制类型后端再根据Content-Type和扩展名二次校验。后端校验不能省因为接口是可以直接调用的绕开前端页面提交一个.exe文件完全可行。文件大小限制我设置在 50MBDjango 的FILE_UPLOAD_MAX_MEMORY_SIZE和 Nginx 的client_max_body_size两处都要配置只配一处会出现“本地能传、服务器上传不了”的诡异问题。文件存储路径我用了competition/{competition_id}/按竞赛分目录并且对文件名做了重新命名避免中文名和非法字符导致服务器兼容问题。这个细节在答辩演示上传文件时能省掉很多尴尬。4.3 评委评分多个评委取均分的算法设计评分模块是业务逻辑的关键点。一个竞赛多个评委每个评委独立打分最终成绩取均分。最开始的简单实现是成绩表加一个final_score字段每次新评分写入时重新计算所有评分的平均数并更新。这个方案能工作但有个隐患如果某评委临时被替换或某份作品被取消资格历史评分删除后均分可能不准而且每次重算的时机容易出 bug。我后来改成视图层动态计算查询成绩时用 Django ORM 的Avg聚合函数现场算均分配合Count统计评委人数。这样数据源永远是最新的代码里没有任何“缓存后忘记更新”的机会。还有一种情况是比赛规则要求“去掉最高分和最低分再取平均”这个用 ORM 不太好写我用了原始 SQL 解决在模型里自定义Manager方法实现。答辩时这段代码可以重点讲一讲属于“理论算法在真实业务中的落地”。4.4 数据可视化用 ECharts 输出竞赛数据大屏系统加了一个数据统计页各学院参赛人数对比、各竞赛报名人数趋势、获奖分布饼图、评委打分分布直方图。前端用 ECharts 实现后端提供几个聚合接口用 ORM 的annotate配合Count、Sum直接在数据库层完成统计返回给前端的就是可以直接用于图表渲染的 JSON 数据。比如各学院参赛人数的统计核心代码就一行Registration.objects.values(user__college).annotate(countCount(id))Django ORM 的价值在这里体现得特别明显。手写 SQL 当然也能实现但 ORM 的返回结构更规整而且对表关联的查询逻辑有更强的可读性。Vue3 里图表组件我用一个BaseChart包装了一下只需要传入 option 配置对象不同图表之间切换数据源即可。可视化页面在答辩现场是最抓眼球的一部分强烈建议所有毕设系统都加。5. 前后端联调实测跨域、响应式与鉴权的排错记录5.1 跨域问题CORS 配置与前端代理的取舍前后端分离后第一个迎面而来的问题就是跨域。开发环境下前端跑在http://localhost:5173后端跑在http://localhost:8000端口不同浏览器默认拒绝携带非简单请求的跨域访问。我最初用django-cors-headers在后端直接放开 CORS方便是方便但放开后前端的所有请求都能打进来和“无鉴权”没什么区别。正确做法分环境开发环境在后端配置允许http://localhost:5173来源生产环境则不允许所有来源而是通过 Nginx 反向代理把/api/路径转发到后端前端请求走同源地址跨域问题根本不存在。开发和生产用不同的配置方式这事我在部署阶段反复折腾了好几次才彻底理清。5.2 Vue3 响应式陷阱表格数据不同步的排查过程这个坑我是真金白银踩出来的。写一个列表页从接口拿到数组后直接赋值给一个reactive声明的数组变量页面却死活不更新。查了半天才发现是 Vue3 响应式代理的问题reactive的深层代理数组整体被替换成新数组时可能会丢失原有响应式连接。排查链路是这样的先在 Vue Devtools 里看数据确实已经更新了页面上却没有反应再检查赋值语句state.list res.data.data看起来没问题最后查文档确认了 Vue3 的响应式机制——对reactive对象的属性重新赋值是响应式的但对象内部数组元素的替换要看触发的方式。解决办法有三个一是用ref声明数组赋值用xxx.value data这是最顺手的二是用state.list.splice(0, state.list.length, ...data)保留引用原地替换三是Object.assign合并。我最终统一用ref方案并且所有列表页都按这个约定写再没出过同类问题。5.3 Token 过期与 Axios 拦截器的统一处理JWT 认证在系统里承担了所有接口的鉴权。登录后前端存两个 tokenaccess短令牌2小时过期和refresh刷新令牌7天过期。正常情况下是 access 过期后用 refresh 换新的 access但这个闭环我一开始没做导致用户用着用着突然就跳回登录页体验极差。后来我在 Axios 响应拦截器里加了统一处理请求返回 401 时先尝试用 refresh token 调用刷新接口成功则更新 access token 并重放原请求失败才清空登录状态跳登录页。这个逻辑说起来简单但写的时候要注意防止并发请求同时刷新 token 的问题我用了let isRefreshing false加一个等待队列的方式保证同时间只有一个刷新请求在飞。这些都是生产环境才会暴露出来的细节写在论文里会让开发过程显得很扎实。5.4 时间字段在不同环境下的显示错乱这个问题的表现是本地测试时间正常部署到服务器后所有报名时间都差了 8 小时。排查结论是 MySQL 时区、Django 的TIME_ZONE、服务器系统时区三者之间没有对齐。我的处理是MySQL 连接参数里加OPTIONS: {init_command: SET time_zone 08:00}同时 Django 设置TIME_ZONE Asia/Shanghai然后把所有涉及时间输出的地方统一交给前端格式化后端一律返回 ISO 标准字符串。从此时间再也没有出过问题。6. 部署、演示与论文写作从代码到答辩的最后一公里6.1 从本地开发到服务器部署的简易路径我部署用的是最常规的方案一台云服务器MySQL 放数据库后端 Gunicorn 跑 Django 应用前端npm run build出来的静态文件交给 Nginx 托管Nginx 同时承担反向代理把/api/请求转发给 Gunicorn。部署有几个容易卡住的细节Python 依赖环境建议用虚拟环境我用了uv来管理比 pip 快得多Django 的settings.py里DEBUG False之后静态文件的收集方式会变需要跑collectstaticGunicorn 配置文件里 worker 数量不要拍脑袋写我按服务器核数设的2 * CPU 1实测效果稳定。前端方面Nginx 需要配置try_files $uri $uri/ /index.html否则刷新前端路由会 404。6.2 演示系统的三分钟演示脚本到答辩阶段我意识到一个残酷的事实代码写得再好演示拉胯一样扣分。我提前准备了三条演示路径每一条都是“开口讲一句业务场景 - 操作 - 看效果”的节奏。第一条是管理员完整创建一场竞赛、审核两个报名、分配评委第二条是评委登录给作品打分打出后立刻看成绩页均分变化第三条是学生登录报名并提交作品然后去个人中心看状态流转。三条路径串起来正好覆盖主链路的每一个核心功能时间控制在三分钟左右。我把所有演示用的账号密码贴在笔记本键盘旁边避免现场登录时手忙脚乱。6.3 论文技术章节的写作思路论文写作和写代码是两种完全不同的思维方式。代码要的是逻辑严谨论文要的是“问题 - 方案 - 验证”这条叙事线。我的论文技术章节没有按前后端模块平铺直叙而是挑了几个核心技术点深入展开权限控制方案、报名并发控制、评分算法、文件上传跨域处理。每个点都是先说明遇到了什么具体问题再讲我的方案最后展示验证结果。这样的写法比“系统包含用户管理模块、竞赛管理模块、作品管理模块……”这种流水账有说服力得多。答辩老师问的问题基本也都围绕这几个点展开因为这些问题代表了你对系统真实的理解程度。当初联调阶段踩的那些坑反而成了论文和答辩里最值钱的素材。最后说一点个人体会。做管理系统类毕设最大的风险不是技术难而是功能看起来“太简单”——担心答辩老师一句“这不就是一个 CRUD 吗”就把自己问住。我自己的应对方式是找两个深水区一个是在并发控制、权限设计、文件处理这类工程问题里做足够的考察和实验一个是把数据统计可视化做得超出预期。这两块投入的时间不多但在答辩效果上的回报是立竿见影的。如果你也在做同类系统建议把精力优先花在数据模型的完整性和核心链路的闭环上功能宁可少而精不要多而糙。系统的报名、审核、评分、发布这四个核心动作能跑通就已经是一个合格的毕设系统了。剩下的那些旁枝末节等核心立住了再加也不迟。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门