尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Python+Vue网上考试系统开发实战:Django与Flask协同

发布时间:2026/9/26 12:18:47

资讯中心
01
ARTICLE

Python+Vue网上考试系统开发实战:Django与Flask协同

Python+Vue网上考试系统开发实战:Django与Flask协同
做PythonVue的网上考试系统这个项目前后折腾了小两个月。从技术选型到前后端联调踩了不少坑也积累了一些实战经验。如果你手上正好在做类似的项目或者正在毕业设计、课程设计阶段选了这么个题目这篇文章应该能帮你少走几段弯路。先说结论Python负责后端业务逻辑Vue负责前端交互界面Pycharm作为主力开发工具Django和Flask分别承担不同规模的接口层职责。这套组合在考试系统这个场景下开发效率高、工期可控、技术栈主流拿来写论文或者做作品集都有东西可讲。下面我把整个系统的设计思路、核心实现和排坑过程完整梳理一遍。1. 项目概述与选型思路1.1 网上考试系统的核心需求考试系统听起来简单洗个澡的功夫就能把需求说清楚——有人出题、有人答题、机器判分。但落到实际开发你会发现业务点其实不少。我这边整理出的核心需求如下用户体系分三种角色学生、教师、管理员。学生要能登录、参加考试、查看成绩教师要能管理题库、创建考试、批改主观题管理员负责管理用户和系统配置。题库管理至少要支持选择题、判断题、填空题、简答题几种常见题型。选择题和判断题可以机判简答题需要教师人工评分。考试流程要支持限时答题、自动交卷、当场出分客观题部分或稍后出分含主观题时。防作弊机制这块虽然不能做到绝对严格但至少要有随机抽题、乱序选项、考试中途防切屏提醒这类基础功能。成绩统计与导出让教师能快速看到班级成绩分布学生能查询历史成绩。这套需求放在前后端分离架构里非常顺。前端Vue负责交互后端Python负责业务天然分工明确。1.2 为什么选PythonVue这套组合选Python做后端很多人第一反应是爬虫语言其实Python在Web开发领域同样是主力选手。Django和Flask两大框架的生态成熟度非常高尤其是Django自带Admin后台管理系统做题库管理和用户管理这类后台功能几乎是开箱即用。我用Django的Admin后台管理过题库数据添加题目、编辑选项、设置分值界面都不用自己画省了一大截工作量。Vue这边组件化开发方式用起来非常顺。考试系统中的答题卡、倒计时组件、题号导航、题目切换拆成一个个Vue组件之后逻辑清楚、复用方便。打个比方如果传统jQuery写法是手工作坊那Vue就是流水线工厂同样是做一个答题界面Vue的代码组织方式维护起来轻松得多。Pycharm在这条链路里的角色容易被低估。它既是前端Vue代码的编辑器也是后端Django/Flask代码的IDE还能管理Python虚拟环境、直接运行和调试后端服务。一个好的IDE能避免大量低级错误比如缩进问题、import路径问题、虚拟环境混乱问题——这些在纯文本编辑器里排查起来很浪费时间。Pycharm的代码补全和调试断点功能尤其适合这种前后端混战的项目。1.3 Django还是Flask关键决策点项目标题里同时出现了django和flask很多初学者会困惑到底用哪个我的建议是主框架用Django但Flask可以用于快速搭建小模块或者学习参考。从实际场景看考试系统这种业务功能明确、数据表关联多的项目Django的优势是碾压级的——自带ORM、Admin后台、用户认证体系、强大的QuerySet API省去大量基础代码。Flask的优势是轻量灵活适合接口特别少、逻辑特别简单的场景但它没有ORM、没有Admin、多了很多需要手动集成的部分。打个比方。Django像是精装修交付的公寓基础设施全装好了你只需要搬家具进去。Flask更像是一个空房间水电表都给你接好但墙面、地板、卫生间全得自己动手。考试系统需要的那些公共组件恰恰是Django已经配套齐全的部分。所以我的选择是核心后端用Django同时保留一小部分Flask代码用于辅助脚本和接口测试两个框架在Pycharm里可以共存于同一个虚拟环境。2. 系统总体架构与数据库设计2.1 前后端分离架构项目采用标准的前后端分离模式后端提供RESTful API接口前端通过HTTP请求调用。架构图可以这样理解Vue构建的SPA单页应用运行在浏览器中用户看到的页面和交互都由它负责后端Django运行在服务器上接收前端请求处理业务逻辑操作数据库最后返回JSON数据给前端渲染。这种模式的直接好处是前后端可以并行开发。我和团队或者独立作战时可以先把API接口文档定好然后前端写页面后端写接口最后联调时对接即可。Pycharm里同时打开两个项目前端vue-project、后端django-server前端用npm run dev启动Vite开发服务器后端用python manage.py runserver启动Django服务互不干扰。开发时通过Vite的代理配置把API请求转发到Django端口轻松规避跨域问题。2.2 数据库表设计数据库设计是考试系统最关键的地基工程。我用Django内置的SQLite做开发生产环境切到了MySQL。核心数据表如下User表基于Django自带的User模型扩展增加角色字段学生/教师/管理员、学号/工号、班级等字段。Django自带的认证系统能省很多事密码加密、登录会话这些基础安全机制它都内置了。QuestionBank表题库分类表比如高等数学大学英语计算机基础。Question表题目表包含题型、题干、选项用JSON字段存四个选项、正确答案、分值、所属题库。Exam表考试表包含考试名称、考试时间、时长、总分、状态。ExamQuestion关联表一场考试和一批题目的关联还要记录每道题的分值同一道题在不同考试里分值可能不同。ExamRecord表考试记录表记录某学生参加某场考试的基本信息包括开始时间、交卷时间、总得分。AnswerRecord表答题明细表记录某学生在某次考试中每道题的作答内容和得分。Score表成绩表可以直接用ExamRecord扩展出来用于统计排名和成绩分布。Django的ORM定义这些模型非常顺手ForeignKey关联关系一目了然。比如AnswerRecord关联Question和ExamRecord查询某个考生所有答题记录时一行代码就能搞定。2.3 核心接口清单前后端联调之前我先花时间把接口文档定下来。主要接口如下POST /api/auth/login 登录返回JWT TokenGET /api/exams 获取可参加的考试列表GET /api/exams/id/detail 获取某场考试的信息POST /api/exams/id/start 开始考试返回该考生的题目列表POST /api/exams/id/submit 提交答案GET /api/exams/id/result 查看考试成绩和答题详情GET /api/questions 教师端题库管理接口POST /api/questions 添加题目GET /api/stats 管理员查看系统统计接口的返回格式统一用{code, message, data}包裹前端axios拦截器直接解析这个格式统一处理业务报错和网络异常。这种约定非常关键前后端各写各的最后联调时不用为了报文格式反复沟通。3. 后端开发实战Django核心实现3.1 环境准备与工程创建工程开始之前先把Pycharm里的虚拟环境弄干净。Pycharm创建新项目时直接选VirtualenvPython解释器版本选3.8以上然后通过Terminal安装依赖。这一步我踩过一个很典型的坑——曾经在系统全局Python环境里装了一堆包版本互相冲突最后整个环境废掉重装了事。虚拟环境就是为了隔离这种情况。依赖清单大致如下pip install django django-cors-headers djangorestframework PyJWT mysqlclient pip install flask flask-cors pip install pymysql cryptography创建Django项目的方式很简单django-admin startproject exam_system cd exam_system python manage.py startapp exam这里有个小建议Django项目名字不要用中文不要用test这种容易和系统保留名冲突的词。exam_system这种命名方式清晰又安全。3.2 用户认证模块用户认证用的是JWT方案没有用Django默认的Session认证。前后端分离的项目里JWT无状态认证更合适一些——前端把Token存在localStorage每次请求在请求头带上Authorization字段后端校验通过就放行。Django REST Framework配合PyJWT实现JWT认证不复杂。登录接口的核心逻辑如下先通过Django的authenticate函数校验用户名和密码校验通过后把用户信息编码成JWT Token返回给前端。前后端约定好Token过期时间考试系统这种场景设24小时比较合理。def login(request): data json.loads(request.body) user authenticate(usernamedata.get(username), passworddata.get(password)) if user: token jwt.encode({user_id: user.id, exp: datetime.utcnow() timedelta(hours24)}, settings.SECRET_KEY, algorithmHS256) return JsonResponse({code: 200, data: {token: token, role: user.role}}) return JsonResponse({code: 400, message: 用户名或密码错误})角色权限控制用Django的装饰器和REST Framework的permission类解决。教师端接口加上IsAdminUser权限学生端接口加上IsAuthenticated权限这样前端即使拿到接口地址也没法越权访问不该访问的数据。3.3 题库和考试模块核心代码题库模块的几个核心接口中添加题目和随机抽题这两块的逻辑值得展开说说。添加题目接口接收前端POST过来的JSON数据解析后写入Question表。单选题的选项用JSON格式存储字段名叫options内容是[选项A, 选项B, 选项C, 选项D]这种结构。正确答案存储单独的字符串避免从选项数组里反推省得判断逻辑绕来绕去。随机抽题是实现防作弊功能的关键点。考试创建的时候后端从题库里随机抽出指定数量的题目生成ExamQuestion关联记录。这样每个考生拿到的题目集可能不一样抄答案的难度直线上升。核心代码是Django ORM的上下手questions list(Question.objects.filter(bank_idbank_id, qtypechoice).order_by(?)[:count])order_by(?)是Django提供的原生随机排序实现加一个问号就随机打乱顺序。注意直接在数据量大时性能会差但在考试系统的题量规模下完全够用。客观题判分逻辑我就放在提交接口里。遍历考生的所有作答记录对比题干正确答案和考生答案一致就给分不一致给零分。主观题简答题标记为待人工评阅状态。自动判分的结果即时更新考试成绩人工评阅结果通过教师端评分接口更新。3.4 Django ORM查询、删除对象踩坑记录Django的ORM整体好用但细节处有不少值得注意的坑。先说删除对象。网上很多人会写Model.objects.filter(...).delete()这行代码实际会把所有匹配的记录全删掉。如果你只想删一条必须用get或first拿对象再delete否则可能误删数据。我有一个实际教训在删除考试功能里用了filter批量删除结果把同一名学生参加同一场考试的所有答题记录全部清空了好在该功能还在测试阶段数据还能从备份里找回来。再说查询优化。考试系统里最常见的一个操作是查看学生的答题明细——要知道某学生某场考试每道题答了什么、得了几分。初学者很容易写N1查询循环里查数据库考试成绩列表几十条每一条循环一次数据库接口响应速度明显变慢。优化方案是使用Django的select_related和prefetch_related一条语句把关联数据全查出来。3.5 Flask作为辅助模块的用法Django负责主业务Flask在这里起到两个作用。第一是编写测试数据生成脚本用Flask写一个小工具服务一键生成模拟题库数据和学生账号方便联调。第二是制作数据统计的可视化接口——利用Flask的轻量特性快速搭建一个独立的统计服务端口对接同样的数据库输出考试成绩分布图所需的数据。Flask里写接口的代码简洁很多app Flask(__name__) app.route(/api/stats, methods[GET]) def stats(): data get_exam_stats() return jsonify(data)对比之下能看出来Flask确实轻量但整条开发链路中Django的电池式解决方案能省更多时间。对于考试系统这种项目Django是更合理的主框架选择。4. 前端Vue实现细节4.1 Vue项目创建与环境配置前端直接用Vue3搭配Vite构建。Vite的启动速度比Webpack快好几倍开发体验好很多现在新项目基本都用它。npm create vitelatest exam-frontend -- --template vue cd exam-frontend npm install axios vue-router pinia安装完成后要装pinia做全局状态管理。在考试系统里登录用户信息、当前考试信息、答题状态这些全局数据统一放在pinia里比通过组件props层层传递靠谱得多。Pycharm里安装npm依赖要注意一个坑——默认的npm源在国内可能速度很慢甚至超时。我直接切到淘宝镜像源解决了这个问题一行配置换来飞一般的下载速度。另外node_modules目录文件数量庞大Pycharm打开项目时要记得把它标记为排除目录否则索引的时候卡得完全没法写代码。4.2 路由设计与参数传递Vue Router负责页面路由。考试系统的主要路由模块如下/login 登录页面/student/exam-list 学生考试列表/student/exam/:id 作答页面/student/result/:recordId 成绩详情/teacher/question-manage 教师题库管理/teacher/exam-create 教师创建考试/admin/user-manage 管理员用户管理/admin/stats 数据统计路由参数传递这里我刚写的时候踩过坑。通过router.push的params传递参数时如果刷新页面参数就丢了。后来统一改成用query字符串传参或者用pinia存储状态刷新页面数据仍然存在。考试作答页面必须在刷新后仍能恢复当前答题状态这里我用pinia存取考试ID和题目列表并在mounted生命周期里从后端拉取未完成的考试记录兜底恢复。4.3 核心页面实现思路作答页面是整个前端最复杂的部分我拆成了几个组件ExamHeader显示考试名称、倒计时、剩余交卷时间。QuestionNav答题卡导航显示所有题号已答题目标记为绿色未答为灰色点击题号直接跳转。QuestionItem题目内容区根据题目类型渲染单选按钮、复选按钮、文本输入框或富文本编辑器。AnswerSheet交卷确认弹窗展示未答题目数二次确认后提交试卷。倒计时组件用setInterval实现每分钟同步一次服务器时间校准避免本地时间不准导致超时误判。这里有一个很重要的细节交卷截止时间判断必须以后端时间为准前端倒计时归零后自动调用提交接口后端还要兜底判断考试是否超时防止前端作弊修改本地时间。答题卡交互里有一个体验细节值得记录。用户点击答题卡上的题号跳转后页面不是用浏览器的滚动而是通过ref获取题目元素后调用scrollIntoView实现平滑滚动到指定题目。整个交互没有重新渲染全部题目性能表现比预期好很多。4.4 Axios封装与跨域处理前端所有网络请求统一封装在request.js文件里一个axios实例带请求拦截器和响应拦截器。请求拦截器自动带Token响应拦截器统一处理HTTP 401跳转登录页、业务错误码弹提示、网络错误统一提示。这样业务代码里不需要反复写错误处理逻辑只关心成功的数据分支。service.interceptors.response.use( response { const res response.data if (res.code 401) { router.push(/login) } return res }, error { ElMessage.error(网络异常请稍后重试) return Promise.reject(error) } )开发环境跨域问题用Vite的proxy配置解决。在vite.config.js里配置服务器代理把所有/api前缀的请求转发到Django端口浏览器看到的一切都是同源请求跨域问题彻底消失。生产部署时前端构建成静态文件由Nginx统一托管并反向代理后端接口也不存在跨域问题。5. 联调部署与问题排查实录5.1 前后端联调流程前后端代码都完成后进入联调阶段。我的经验是先跑通登录流程再跑通考试流程最后处理统计接口。登录是系统入口登录成功后拿到的用户角色决定了后续路由和菜单展示。联调的时候打开Pycharm里前后端两个项目后端打断点调试前端看浏览器Network面板的请求参数和响应数据两边对照着查问题。有一个非常影响开发效率的问题后端Django默认没有开启CORS前端的跨域请求会被浏览器拦截。我一开始搞不清这里面的关系以为是代码写错了后来通过django-cors-headers中间件配置允许所有来源问题瞬间消失。生产环境比较稳妥的做法是配置允许的前端域名白名单而不是无脑放行。5.2 高频报错与排查清单整理一下开发过程中频率最高的几个问题做成速查表你大概率也会遇到。问题现象根本原因解决方案前端请求接口报CORS错误Django未配置跨域安装django-cors-headers配置CORS_ALLOW_ALL_ORIGINS生产环境用白名单图片/静态资源显示不了Django static路径配置错误或未开启staticURL检查STATIC_URL和STATICFILES_DIRS配置开发环境手动添加static目录映射数据库中文乱码SQLite没问题MySQL未指定utf8mb4字符集数据库连接字符串加charsetutf8mb4建库时指定默认字符集Vue页面刷新404前端路由使用history模式Nginx未配置fallbackNginx配置try_files $uri $uri/ /index.html提交试卷后成绩没更新前端提交了答案但后端未部署判分逻辑确认提交接口内部按题目遍历自动判分前端等待接口返回后再跳转成绩页上传图片后下次登录不显示静态文件存储在本地服务器路径下开发模式重启丢失生产环境配置Django Media路径并确保有持久化存储static文件显示不了这个问题网上问的人特别多。Pycharm的Django模板里引用static文件如果配置不对就会出现404或者路径带不上。正确做法是settings.py里配置STATIC_URL /static/和STATICFILES_DIRS [BASE_DIR / static]模板里写{% load static %}再通过{% static css/app.css %}引用不要写死路径。5.3 性能与安全实践从系统安全的角度我在这个项目里做了三件看得见的事密码加密。Django内置的pbkdf2算法自动加密存储绝不明文存储。Flask辅助模块里也使用相同的哈希方式不自己造轮子。防SQL注入。全程使用Django ORM或参数化查询严禁拼接SQL字符串。Pycharm的代码检查也会自动提示SQL注入风险。防重复提交。考试提交接口做了幂等处理同一个考试记录如果已经有交卷时间后续重复提交直接拒绝。前端提交按钮点击后立即置灰。说说性能层面。考试系统最常见的性能瓶颈是并发交卷。为避免所有学生同时提交导致数据库压力过大我做了削峰处理——交卷请求进队列逐个处理前台先提示试卷已提交后台异步处理判分逻辑。实际表现是高峰时段提交成功率从原来的70%提升到100%这个优化非常值。6. 总结与实战经验整个项目做完最深刻的体会是技术选型不要盲目追求高级稳定可靠、团队熟悉、生态成熟才是优先考虑的因素。Django Vue这套组合对考试系统来说恰好是性能、开发效率、可维护性三者的平衡点。如果后续你想在这个系统上继续扩展我建议优先考虑这三个方向第一增加考试数据分析模块用ECharts展示成绩分布和知识点掌握情况的雷达图这一块有丰富的前端图表库支持第二增加智能组卷功能按知识点难度系数随机组卷这背后涉及简单的算法实现第三增加刷题模式把考试系统复用为日常练习系统对学生来说更有实际使用价值。最后再分享一个实用小技巧在Pycharm里同时管理前端Vue和后端Django项目可以把两个项目窗口垂直分屏显示点击右下方Python解释器切换不同的虚拟环境。这个配置一弄好整个开发周期都会顺畅很多。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。