资讯详情

资讯详情

Django+Vue构建公务员备考平台:Flask迁移与前后端分离实践

最近把一套公务员应届生复习备考平台的项目代码重新整理了一遍觉得里面很多选型决策和踩坑细节值得记录下来。项目本身不算复杂面向应届生提供行测、申论的在线刷题、错题整理、模考记录和成绩分析前后端分离后端一开始用的是 Flask后来因为管理后台、ORM、认证这些环节越来越吃力主体切到了 Django前端使用 Vue 全家桶整个开发调试都在 PyCharm 里完成。这篇分享就把整个平台的拆解思路、核心功能实现、实操流程和排查过的坑完整过一遍给正在做类似学习类平台的朋友一个能直接抄作业的参考。1. 项目整体设计与技术选型1.1 为什么从 Flask 迁到 Django一次真实的选型对比标题里同时出现了 Flask 和 Django不是笔误而是这个项目真的经历了从 Flask 到 Django 的切换。第一批原型我用了 Flask那时候想法很单纯平台早期只有刷题、登录两个主要模块Flask 轻量写几个路由配合 Jinja2 模板就能跑起来快速验证需求完全够用。但随着题库管理、用户角色、错题本、模拟考试、成绩统计这些模块陆续加进来Flask 的“轻量”就开始变成负担了。Django 自带 Admin 后台、ORM、迁移机制和自带认证体系等于把一套成熟的后台地基直接给你。在公考复习平台里管理后台的需求特别重运营要批量导入各科目试题、配置模考时间、管理用户状态如果这些全都自己用 Flask 写一遍少说也要两周时间而且安全性和可维护性都不如 Django 现成的方案。项目切到 Django 之后我保留了一个 Flask 微服务用来做高频的刷题提交接口。原因很实际刷题提交时前端会频繁发请求Django 的请求处理模型相对“重”每次都要走完整的中间件和 ORM用 Flask 单独拆一个轻量接口对读多写少、且不涉及复杂业务逻辑的场景更加灵活。于是架构变成了 Django 主站负责用户、题库、管理后台等核心业务Flask 微服务负责刷题提交和答题记录的快速写入两者都跑在同一台服务器上通过内部端口通信。这个混合架构在实践中运行得很稳也是标题里两个框架都出现的原因。1.2 前后端分离架构Vue 与后端的协作方式前端选用 Vue 的原因很直接它的生态在国内最成熟组件化和状态管理有一套清晰的模式社区里有大量现成的后台模板和移动端适配方案对于一个人开发或者小团队开发来说效率远高于从零搭原生 JS。平台采用前后端完全分离Vue 负责页面渲染和用户交互Django 通过 REST API 提供数据Flask 微服务也单独暴露刷题提交接口。前后端通过 JSON 传递数据认证使用 Token 机制。这里有一个关键设计Django 主站使用 JWTJSON Web Token做用户身份认证Flask 微服务不直接处理用户密码而是共享同一个 JWT 密钥在收到请求时用同一个算法校验 Token再从 Token 中解析用户 ID。这样两个服务之间不需要每次查询用户表减轻了 Django 的压力。Vue 端会在 Axios 拦截器里统一加上 Authorization 头遇到 401 时自动跳转登录页用户切换页面时感觉不到两个后端的存在。1.3 开发环境PyCharm 的配置与工程化整个项目在 PyCharm 中开发IDE 的作用不只是写代码更重要的是让多服务协同调试变得顺畅。我用 Professional 版本因为需要同时运行 Django 和 Flask 两个解释器。配置上在 PyCharm 中分别为两个服务创建了两套运行配置一套是 Django Server指定项目目录和端口 8000另一套是 Flask 应用的 Python 配置指定启动脚本和端口 5001。前置脚本里加了环境变量判断避免共用同一个端口。比较重要的一个工程化操作是统一 Python 依赖管理。项目要求 Python 版本在 3.9 以上我在 PyCharm 的项目解释器里创建了一个虚拟环境用 requirements.txt 管理 Django、Flask、djangorestframework、django-cors-headers、PyJWT、gunicorn 等依赖。PyCharm 的数据库插件也帮了大忙我可以直接连上 MySQL 查看试题表结构调试 ORM 查询时还能看到官方 SQL这对优化查询效率非常有效。用 PyCharm 的 “Save as Run Configuration” 功能把两条启动命令保存下来每次开发时一键同时启动省去了频繁切换终端的麻烦。2. 核心功能模块解析2.1 用户系统应届生身份与角色权限平台面向应届生用户注册时需要填写毕业年份、所学专业、目标报考省份等字段用于后续的个性化推荐。Django 自带的 User 模型不能满足这些额外属性我采用继承 AbstractUser 的方式扩展了 Profile 模型用 OneToOne 字段关联。这样既能复用 Django 的密码哈希和管理后台又能保存自定义信息。权限设计上区分了学生角色和运营角色。学生只能查看自己的刷题记录、错题本和成绩报告运营角色可以在 Django Admin 中导入试题、管理模拟考试、查看用户统计。为了不让用户通过修改前端跳转越权所有 API 在 Django 视图里都用permission_classes做二次校验。比如获取错题本的接口除了要求 JWT 有效还会校验request.user.is_student如果角色不匹配直接返回 403。这个细节在很多类似平台上容易被忽略但公考复习平台涉及大量用户行为数据越权访问会造成成绩泄露不能省。2.2 题库管理多科目刷题与试题导入题库是复习备考平台的核心资产。题型包括常识判断、言语理解、数量关系、判断推理、资料分析以及申论主观题。每种题型对应不同的做题策略和展示方式。数据库中设计了 Question 模型字段包括科目、题型、题干、选项JSON 格式存储、正确答案、答案解析、难度等级、所属考点。选项用 JSON 字段存储而不是建一个独立选项表因为刷题场景下选项和题干是整体读取的分开查询只会增加 JOIN 成本。运营人员往系统里导入试题时最常遇到的是 Word 和 Excel 格式的试题。Django Admin 原生不直接支持文件导入我写了一个自定义管理命令import_questions支持读取 Excel 模板和 Word 文档。对于 Excel使用 openpyxl 逐行读取按模板列名映射到模型字段对于 Word需要先将题目文本整理成标准格式再通过正则表达式解析题干和选项。这里有个很重要的数据清洗逻辑解析前必须去除大段空白、跨页的页眉页脚、图片占位符否则会出现题干和上下题粘连的情况。导入后还会做一轮校验如果某题的四个选项中只有三个或者正确答案的字符不在选项集合里会被标记到异常报告文件中运营人员手动处理后再重新导入。2.3 学习记录错题本与复习计划错题本是所有备考类产品的标配但做得是否好用直接决定用户留存。我设计的错题本不只是简单记录“做错了哪道题”而是会记录用户第一次做错的答案、错误时间、错误类型知识点不熟、粗心、审题失误用户可以在错题详情页看到自己当时的作答和标准答案的对比并标记“现在会了”或“仍然不会”。系统会根据错误类型自动打标签后续复习时用户可以按标签筛选。复习计划模块比较复杂。每个用户首次登录时会做一个能力测评根据测评结果和备考剩余天数系统生成一份粗略的周计划。计划由 Django 的定时任务每天自动生成当天需要完成的题目数量和知识点任务。用户完成进度会实时同步到计划表中进度条由 Vue 前端渲染。后端的核心计算逻辑是将“今日应完成题数”按科目权重拆分比如一周前三天侧重行测后两天侧重申论周六做整套模考。这些规则全部放在一个独立的study_plan_service.py中方便后续调整算法。2.4 数据可视化成绩趋势与薄弱项分析成绩分析模块的目标是让用户一眼看出自己还有多少差距。前端使用 ECharts 图表库后端提供聚合接口。例如获取近十次模拟考试的成绩曲线Django 视图会先从 ExamRecord 表中查询该用户所有考试记录按时间排序后返回日期和各科得分Vue 端直接渲染折线图。薄弱项分析相对复杂我们把每道错题的难度系数、考点、耗时和正确率汇总到一起使用一个简单的加权公式计算某个考点的掌握度。掌握度 该考点正确次数 / 该考点总做题次数再结合最近一周的做题变化趋势进行修正。如果连续三天在某个考点上正确率低于 50%系统会在复习计划里增加该考点的专项训练。这个逻辑不涉及复杂机器学习但非常实用帮助用户在有限时间内把精力放在最能提分的部分。3. 实操过程从零搭建平台的核心步骤3.1 后端Django 主站 Flask 微服务的搭建流程首先创建 Django 项目使用虚拟环境隔离依赖。命令大致是python -m venv venv source venv/bin/activate # Windows 下是 venv\Scripts\activate pip install django djangorestframework django-cors-headers PyJWT mysqlclient gunicorn openpyxl django-admin startproject exam_platform cd exam_platform python manage.py startapp users python manage.py startapp questions python manage.py startapp records数据库选用 MySQL在 settings.py 中配置连接信息并通过migrate同步数据表。为了让 Vue 前端能访问 API安装django-cors-headers并白名单了本地开发地址和后端域名。Django DRF 的视图集配合 ModelSerializer把题库、错题、考试记录的 CRUD 接口快速暴露出来。对于自定义的复杂查询直接使用APIView配合 ORM 的annotate和aggregate方法实现聚合统计。Flask 微服务部分单独建一个flask_submit_service文件夹app.py 中使用Flask初始化一个只处理POST /api/submit_answer和POST /api/batch_submit的应用。Flask 中使用flask-cors处理跨域同时加入和 Django 相同的 JWT 校验逻辑。两个服务通过 PyCharm 中不同的端口启动生产环境用 Nginx 统一代理。这样刷题提交这种短平快的请求走 Flask复杂的考试记录和用户数据走 Django各得其所。3.2 前端Vue 组件化开发与接口联调Vue 部分使用 Vue CLI 创建项目安装 vue-router、vuex、axios 和常用的 UI 组件库 Element UI。页面划分包括登录注册、首页、题库列表、做题页、错题本、考试记录、成绩分析、个人中心、管理后台。其中做题页是整个平台的灵魂它由多个子组件组成题目展示组件、选项组件、答题卡组件、解析抽屉、计时器。每次提交答案时会先执行前端校验选项是否为空再通过 Axios 调用 Flask 微服务的提交接口同时把答题结果同步到 Vuex用于更新答题卡状态。接口联调中最常见的问题是字段命名不一致。Django 后端习惯用下划线命名例如question_content前端 JS 更习惯驼峰需要统一。项目中我在封装的request.js里做了拦截对返回字段进行自动转换用一个camelize函数将下划线转成驼峰。这样后台返回的question_content在组件里写作questionContent可读性和维护性都好很多。此外因为后端有两个服务Axios 的 baseURL 在开发环境通过.env.development文件区分一个配置成http://localhost:8000/api另一个配置成http://localhost:5001/api运行时根据NODE_ENV自动加载对应环境变量。3.3 部署公考平台的服务器部署与安全配置部署阶段选择了一台 Linux 服务器使用 Nginx Gunicorn 部署 Django用waitress或gunicorn都可以部署 Flask但这里 Flask 只承受少量高频请求直接用 gunicorn 的多线程模式也能处理。具体流程是先将代码上传到服务器安装依赖执行迁移和静态文件收集然后用 systemd 配置文件管理 Gunicorn 进程最后在 Nginx 中配置反向代理。Nginx 的配置里需要区分两个 upstream/api/main/代理到 Django 的 8000 端口/api/submit/代理到 Flask 的 5001 端口前端静态资源直接交给 Nginx 托管。安全方面做了几个基础加固Django 的DEBUGFalseALLOWED_HOSTS配置为实际域名强制 HTTPS使用 Nginx 把 HTTP 请求 301 到 HTTPSJWT 密钥使用环境变量管理不写死到代码里用户密码用 Django 默认的 PBKDF2 哈希保存。还有一点很容易被忽视就是文件上传路径的权限问题。平台允许用户上传头像如果没有限制上传文件的类型和大小可能会被恶意请求用超大图片拖垮服务器。我在 Django settings 中设置了DATA_UPLOAD_MAX_MEMORY_SIZE并且在保存文件之前校验扩展名和文件头。4. 常见问题与排查技巧实录4.1 前后端跨域与 Session 问题本地开发时Vue 在 8080 端口Django 在 8000 端口直接请求会遇到跨域问题。使用django-cors-headers后跨域请求可以发出但还有一个坑Django 的 CSRF 保护默认会对非安全请求做校验而 JWT 认证模式下前端不会自动携带 CSRF Token。解决方法是把需要 JWT 认证的接口标记为csrf_exempt或者将 CSRF 中间件从 Django 的认证流程中绕过仅对 Admin 后台保留 CSRF 保护。这个配置方式在文档里有明确说明但很多人会漏掉导致前端 POST 请求一直 403。另外如果使用 Session 认证跨域时还要配置CSRF_COOKIE_DOMAIN和CSRF_COOKIE_SAMESITE。项目直接用 JWT 之后这套问题完全消失了因为前端不再依赖 Cookie而是把 Token 存在 localStorage 中。建议做前后端分离项目时尽量使用 Token 认证省去大量跨域调试时间。4.2 题库导入性能优化Excel 导入题库时最痛苦的场景是运营人员一次性导入几千道题如果用 Django ORM 逐个save()服务器会卡死整个过程可能要几分钟。优化思路很简单改为批量插入。Django 的 ORM 提供了bulk_create()一次可以创建一批对象批量大小设为 200。导入前先把 Excel 数据解析成一个列表再分批调用bulk_create()10 秒内就能完成几千道题的写入。如果量更大还可以使用INSERT ... ON DUPLICATE KEY UPDATE类的原生命句但一般用不上。还有一种情况是解析大文件时内存占用过高。我的处理方式是不把所有行一次性读入而是用 openpyxl 的iter_rows()流式读取每次只处理一行数据配合异常捕获即使中间有一行格式错误也不会中断整个导入流程。导入结束后生成一个报告文件用表格列出每条失败原因方便运营同学定向修复。4.3 备考数据的并发访问与缓存用户在刷题时如果同时点击“下一题”和“提交答案”可能会后端收到两个相同接口的并发请求。虽然 JWT 校验没有影响但写入数据库时会出现记录重复。解决思路是使用乐观锁在答题记录表中增加一个递增的version字段提交时带上上一次获取的版本号如果版本号不一致说明这次提交已经过期则返回冲突提示前端自动刷新当前题目状态。这样既保证了数据一致性也避免了下游统计出错。对于热点数据比如首页公告和热门考点列表Django 没有直接使用缓存框架而是在数据库层加了一层二级缓存用django.core.cache的cache.set(key, value, timeout)把接口响应存进 Redis。这个操作实现简单但对性能提升很可观。公考复习平台的特点是用户访问集中在晚上七点到十点若没有缓存高峰期数据库压力会很大。我实测过把首页数据缓存 5 分钟后接口响应时间从 300ms 降到了 20ms 以内用户体感明显提升。4.4 移动端适配与响应式踩坑复习备考场景中用户用手机刷题的占比超过七成所以前端响应式适配非常重要。项目中使用了 Viewport 和 Flex 布局在组件尺寸上统一用 rem 单位。踩过的一个坑是微信内置浏览器的字体大小设置当用户在手机系统里调整字体大小后Vue 页面上的 em 和 rem 长度会跟着变导致布局错乱。解决办法是在入口 HTML 的viewportmeta 中设置user-scalableno并在全局 CSS 中重置字体缩放必免页面元素被拉垮。另外一个移动端特别烦人的问题是输入框被软键盘顶起。做题页中需要用户输入申论答案但在 iOS 上使用position: fixed的底部按钮会被键盘遮挡。后来我改用postcss-px-to-viewport将固定尺寸转成 vw同时在键盘弹起时用window.addEventListener(resize)动态调整容器高度才算彻底解决。这些细节在桌面端开发时根本遇不到只有在移动端适配测试的时候才会发现建议项目早期就把手机端作为首要目标而不是最后再做兼容。5. 开发过程的心得与可扩展方向这个平台从最初的原型到最终上线前后花了大概八周时间。最深的体会是技术选型不是越高级越好而是越匹配业务场景越好。公务员考试复习平台核心价值在“题多、题准、错题管理高效”这几个功能 Django 和 Vue 的组合已经非常够用。Flask 在项目中作为轻量接口的补充也不是因为 Django 不行而是这种“主重辅轻”的架构能让不同框架做自己擅长的事而且可以随意替换成 Node 或 Go 写的微服务而不影响主流程。如果后续想扩展可以加入几个实用功能一是支持 Markdown 格式的申论参考答案方便用户对比自己写的答案时直接看重点标记二是引入智能刷题推荐算法基于用户掌握度动态调整出题难度替代目前固定比例的抽题逻辑三是增加刷题排行榜和每日打卡激励用游戏化机制提升应届生坚持备考的动力。数据层面可以为管理员设计一个数据看板展示每日新增用户、活跃刷题数、知识点正确率等核心指标用来反哺题库建设。整个项目代码结构清晰模块之间耦合度低扩展这些功能都只需要在对应模块里新增接口和组件不会动到主干逻辑。最后再分享一个实操小技巧排查问题时在 PyCharm 中同时开启 Django 和 Flask 的断点调试比只靠日志效率高很多。但要注意在调试模式下关闭代用生产环境的缓存否则经常调试完发现改的代码没有生效其实是缓存了旧接口。把这个设置放到环境变量中按需切换会省下不少橡皮擦时间。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →