ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Django+Flask+Vue构建在线刷题系统:从数据建模到部署全指南

Django+Flask+Vue构建在线刷题系统:从数据建模到部署全指南 公务员考试练习系统听起来就是个在线刷题的网站但实际上手要处理的东西比想象中多得多题库怎么组织、错题怎么记、模拟卷怎么组、成绩怎么统计每一个点都能把人绕晕。我当时的方案是 Python 生态全栈做下来Django 管核心业务、Flask 做工具型接口、前端用 Vue 搭交互界面开发调试全部在 PyCharm 里完成。这套组合的好处是每个环节都有人成熟的轮子遇到问题搜资料也方便非常适合想拿真实项目练手的 Python 学习者。这篇文章我按实际开发顺序来写把技术选型、数据建模、前后端联调、部署踩坑这几块一次讲透。如果你正打算做一个在线练习系统不管是公务员考试、驾考刷题还是考研题库核心思路都通用可以直接照着搭。1. 项目整体设计与技术选型思路1.1 为什么是 Django Flask 双框架而不是二选一很多人在 Django 和 Flask 之间纠结过我的建议很直接如果你是做管理系统、后台、内容类网站Django 的 Admin、ORM、认证体系可以帮你省掉一半工作量如果只是一个小服务、一个工具接口、一个爬虫壳子Flask 的轻量和灵活更顺手。这个项目我之所以两个都用不是炫技而是业务上确实有分工需求。核心业务比如用户注册登录、题库管理、答题记录、错题本这些用 Django 做非常稳。Django 自带后台录入题目、维护分类、查看用户数据都很方便不用额外写一堆管理页面。而模拟试卷生成、成绩数据导出、统计报表这类偏向工具型、辅助型的接口用 Flask 写更轻快启动快、路由简单不需要背上 Django 那一套中间件和配置。我在实操的时候Django 跑在 8000 端口提供主业务接口Flask 跑在 5000 端口提供辅助接口两个服务共用同一个数据库前端 Vue 统一代理请求。项目跑起来之后你会发现这种“一重一轻”的组合其实很舒服重业务在 Django 里慢慢打磨轻量功能在 Flask 里随手就写完了两个框架的代码井水不犯河水逻辑边界非常清晰。当时也认真对比过 Flask 和 FastAPI。FastAPI 的异步性能和自动接口文档确实香但考虑到这个项目里大量数据操作都是简单同步查询Flask 的生态资料、插件、部署方案都更成熟踩坑成本低所以最终选了 Flask。新手入门的话我也建议先用 Flask 把基础打牢再去看 FastAPI 的异步玩法。1.2 前端为什么选 Vue而不是 Django 模板公务员考试练习系统本质上是一个强交互应用。考生答题要点选选项、要倒计时、要交卷判分管理员要管理题目、查看数据这些如果用 Django 模板配合 jQuery 做页面状态一多就非常痛苦。Vue 的组件化开发正好解决这个问题一个答题卡片是一个组件一个计时器是一个组件数据变化自动驱动视图开发体验完全不一样。我选的是 Vue 3 Vite 这套组合。Vite 的冷启动速度快到离谱改代码热更新基本秒级生效比老一代的 Webpack 开发服务器舒服太多。Vue 3 的 Composition API 在管理计时器、路由守卫、状态共享这些场景下也比 Options API 更清晰写完一遍之后基本不想再回去用 Vue 2。我负责任地说只要项目包含表单交互、列表筛选、动态渲染这些需求前端用 Vue 是性价比最高的选择。整个项目做下来前端代码量大概三千多行如果硬用模板渲染代码量得翻一倍页面复杂度和维护成本也会高很多。1.3 PyCharm 开发环境配置开发工具我一直在用 PyCharm。这个项目的后端有 Django、Flask前端有 VuePyCharm 的优势在于它能在一个 IDE 里把 Python 解释器、虚拟环境、Node 环境、终端、数据库工具全部管理起来不用来回切换窗口。日常配置我建议这样弄先用 Python 自带的 venv 创建虚拟环境然后在 PyCharm 里把解释器指到虚拟环境里这样 pip 安装的包只影响当前项目不会污染全局。PyCharm 免费社区版其实也能开发 Django 和 Flask只是专业版有一些额外功能比如数据库可视化管理、远程部署个人开发用到的不多社区版完全够用。插件方面我强烈推荐装一个 Fitten Code这是目前我用过的补全速度最快的 AI 插件写 ORM 查询、Vue 组件这些重复代码的时候补全效率直接翻倍。另外装上中文语言包菜单汉化之后新手操作起来省很多事。还有一点要注意PyCharm 里导入第三方库比如 pandas、numpy失败八成是解释器没选对检查一下右下角的 Python 解释器路径别把系统 Python 和虚拟环境弄混了。2. 题库建模与 Django 后端核心实现2.1 公务员考试练习系统的数据模型设计公务员考试分行测和申论行测里又有常识判断、言语理解、数量关系、判断推理、资料分析这五大类。题目类型也比较复杂有单选、多选、判断还有申论这种开放性文字题。所以数据模型不能拍脑袋随便建我设计了三张核心表题目表、分类表、选项表。题目表是题库的核心字段包括题干、解析、题型、难度、所属分类、答案。单选题和多选题的答案字段类型不一样单选可以存一个字符串多选就得用逗号分隔的字符串或者存 JSON。我这里选择把所有题型统一抽象题目表里存题干和解析选项单独建一张表这样单选、多选、判断是与否当作两个选项都能兼容设计上反而是最简单的。用户相关的表也分了角色。普通考生表用于个人刷题练习管理员直接复用 Django 自带的 User 模型配上 Django Admin 就能管理题库。答题记录表和错题本表是练习系统的核心每次答题都插入一条记录记录题目 ID、用户 ID、选项、是否答对、答题用时错题本则是在答错的时候自动同步方便用户后续针对薄弱点专项训练。这里有一个容易踩的设计坑答题记录和错题本不能合并成一张表。答题记录是流水性质的数据量会越来越大需要保留完整的过程错题本是用户维度的聚合视图如果直接过滤答题记录表来展示错题每次查询都要扫大量数据一旦数据量上来就非常慢。我当时就是先合并成一张表结果刷了几天题之后接口响应越来越慢后来改成独立错题表才解决。2.2 Django 建 App 与 ORM 查询删除实战Django 的 App 划分我一开始就规划好了一个 accounts 管用户一个 questions 管题库一个 practice 管练习记录。命令就一条python manage.py startapp questions。新手容易犯的错是把所有功能塞进一个 App 里几百个 View 堆在一起根本没法维护。ORM 操作里查询是最常用的。Django ORM 是惰性查询写 Book.objects.all() 并不是马上执行 SQL而是等真正用到结果才查数据库。很多人调试时觉得“代码执行了但没数据”先想想是不是惰性查询的问题。实际业务里我会大量用 filter 和 exclude比如查数量关系分类下的中等难度题Question.objects.filter(category数量关系, difficulty2)然后在条件上继续用.exclude()排除掉已经做过的题。删除这块我要重点强调。题目、用户的删除是管理行为直接 delete() 没什么问题但答题记录这种统计型数据绝对不能硬删。学员练完题之后反馈“我明明做了 100 题统计里只有 80 题”十有八九是因为我误用了硬删除把答题记录删掉了。正确做法是软删除在表里加一个is_active字段删除操作变成更新操作查询条件永远多一个is_activeTrue。再分享一个踩过的坑Django 的 delete() 会触发级联删除。如果 User 表关联了答题记录表你把用户删了他的几百条答题记录也跟着没了。所以在设计外键的时候要对答题记录这种子表明确设置on_deletemodels.CASCADE的例外情况或者干脆用软删除保护起来。还有一个细节批量删除时 ORM 不做模型层清理只发一条 SQL主表删掉了但关联数据还在所以涉及关联表时一定要看清楚结构。2.3 Flask 辅助服务的分工与实现Flask 在这个项目里做了三件事模拟试卷生成、成绩统计报表、Excel 导出。这些功能如果全塞进 Django 里会让主服务的职责臃肿但放在 Flask 里就非常轻量几十行代码一个服务就搞定了。模拟试卷生成的核心是随机抽题策略。我配置了一套规则每个模拟卷包含 120 道题严格按照行测考卷的比例分布资料分析 20 题、判断推理 35 题、数量关系 15 题等难度按 3:5:2 的比例分配简单 30%、中等 50%、较难 20%。Flask 里实现就是从数据库里按分类和难度筛出候选池再用random.sample做不重复抽取最后把试卷结构返回给前端。成绩统计和导出用到一个技巧Django 项目和 Flask 项目是两套代码但不能有两套数据库配置。我的做法是单独写一个db_config.py统一从环境变量读取数据库连接信息Flask 和 Django 都用这个配置文件两边连同一个数据库。后来我把 SQLite 换成了 PostgreSQL只改了这一个配置文件的连接串两个服务同时生效没有动任何业务代码。Flask 的部署也比 Django 简单。本地调试就flask run开发环境我挂了flask_cors处理跨域上线后换 gunicorn 跑服务命令也就一行gunicorn -w 4 -b 0.0.0.0:5000 app:app。整体维护成本非常低。3. Vue 前端搭建、路由与前后端联调3.1 Vue 环境安装与项目初始化如果你从零开始搭 Vue 环境先检查 Node.js 版本。Vue 3 和 Vite 要求 Node 版本在 16 以上老版本直接报错。然后执行npm create vuelatest这是目前官方的项目创建方式它会让你选择要不要 TypeScript、Vue Router、Pinia 等模块按需勾选就行。安装依赖的时候国内环境最大的坑就是 npm 源慢。我建议把镜像源切到国内执行命令npm config set registry https://registry.npmmirror.com之后装包速度直接起飞。热门依赖比如 axios、element-plus、vue-router装了基本不会出问题。如果遇到某个包编译报错最先检查是不是 Node 版本和包版本不兼容其次才是清理缓存重装。我建了这几个页面组件HomeView 是首页展示考试分类和统计入口LoginView 是登录页PracticeView 是刷题页支持按分类练习和随机练习ExamView 是模拟考试页开考后进入不可退出的全屏模式RankView 是成绩排名。用 Vue Router 注册路由路径和组件的对应关系一目了然。3.2 路由守卫、插槽和答题计时交互Vue Router 的路由守卫是这个项目的“门卫”。我在全局前置守卫里做登录校验router.beforeEach((to, from, next) { if (to.meta.requiresAuth !token) next(/login); else next(); })这样没登录的用户访问任何内部页面都会被自动弹回登录页避免每个页面里重复判断。组件插槽是 Vue 里特别好用的功能。答题卡组件我设计成一个带插槽的容器组件内部只负责渲染倒计时和交卷按钮具体的题目内容、选项样式由调用方传入。这样行测的选择题、判断里的空格、申论的作文题都能复用同一个答题卡外壳代码量直接减少一半。插槽还有个好处就是页面布局更灵活比如资料分析题需要在题目旁边放一组图表直接用命名插槽插进图表区域就行。答题页面最大的坑是计时器。我一开始在 data 里挂了个定时器每秒钟更新倒计时结果用户在多个页面间切换、组件重复挂载定时器越积越多页面越来越卡。正确的做法是在组件的onUnmounted生命周期里clearInterval清理计时器同时把计时器实例保存到组件变量里不要每次创建新的。另外模拟考试的时间计算最好用服务端时间为准前端本地计时容易作弊也不可靠。3.3 跨域、登录态与 Axios 拦截器前后端分离必然会遇到跨域问题。Django 那边我在settings.py里配置了django-cors-headers库加上CORS_ALLOWED_ORIGINS允许 Vue 的开发地址访问。Flask 那边加上flask_cors库一行CORS(app)搞定所有跨域请求。千万别去想用 JSONP 之类的土办法现代项目直接用 CORS 方案最省事。登录态我用 JWT。Django 端使用simplejwt库用户登录成功后返回 access_token 和 refresh_token前端把 token 存进 localStorage。Axios 封装了一个统一的请求实例请求拦截器里自动加上Authorization: Bearer token当接口返回 401 时说明 token 过期再用 refresh_token 请求一下新的 access_token刷新失败就跳回登录页。这里有一个我好心提醒你提前想清楚的细节前端请求要区分 Django 和 Flask 两个服务地址。我在.env.development里分别配了两个环境变量VITE_API_MAIN_URL和VITE_API_UTIL_URLAxios 封装里暴露两个独立实例一个走主服务一个走工具服务这样模拟试卷的接口和统计导出接口就不会混在一起。4. 实操过程与踩坑记录4.1 从零到一的项目搭建完整流程我把整个项目的搭建流程整理成了一套可以照着走的步骤每一步做完都有明确验证标准方便定位问题。第一步在 PyCharm 里创建 Django 项目。选中 venv 虚拟环境终端执行django-admin startproject exam创建工程再执行python manage.py startapp questions创建题库应用。跑起来python manage.py runserver看到默认欢迎页说明 Django 基础环境没有问题了。第二步配置数据库和后台。在settings.py里注册应用、配置数据库连接然后执行迁移命令生成数据表。创建 superuser 之后进入 Django Admin把题目分类和几道测试题目录入后台。这一步能跑通说明数据管理和基础模型没有问题。第三步编写核心业务接口。我用 Django REST Framework 写接口创建 serializers 和 viewsets把「按分类刷题」「提交答案」「记录错题」「查询统计」这几个核心接口写出来用 Postman 逐个测试通过。第四步搭建 Flask 服务。新建一个 Flask 项目目录写模拟试卷生成和成绩导出两个模块测试通过后启动在 5000 端口和 Django 服务同时运行。第五步创建 Vue 前端项目。初始化完成后安装 element-plus 组件库页面表格、表单、弹窗都有现成的、axios、vue-router。用 Vue Router 搭好页面框架在空组件里先渲染一个标题栏确认前端脚手架完全跑通。第六步对接接口。在 Axios 封装里填上两个服务的地址把登录、题库列表、答题提交、成绩统计这几个核心流程从前端到后端全部串起来跑一遍。第七步写 Dockerfile 和部署配置。把两个后端服务和前端构建产物分别容器化用 docker-compose 统一编排启动。这套流程从零开始一个周末能跑通核心功能。但注意这里每一步都不是单纯的“往下走”每走一步都要回到浏览器里点一遍页面才能保证不把烂摊子留到后面。4.2 常见问题排查速查表我把实际开发里遇到的高频问题整理成一个速查表每个问题都是真实踩过坑的不是从文档里抄的。问题现象根本原因解决方案Django 接口返回中文乱码数据库连接未指定 UTF-8或客户端未设置 Accept 头检查 DATABASES 配置项OPTIONS里的charset统一为 utf8mb4前端请求接口报 CORS 错误Django 未安装 django-cors-headers 或配置了错误的允许域名添加CORS_ALLOWED_ORIGINS并确认后端服务正确加入中间件Vue 打包部署后接口 404前端 baseURL 还是写死的 localhost打包前把.env.production的接口地址改为线上域名或配置 nginx 反向代理Flask 和 Django 同时访问 SQLite 报错SQLite 只允许单进程写两边同时读写冲突开发阶段分时访问生产环境必须换 PostgreSQL 或 MySQLPyCharm 安装 pandas 失败解释器路径选错装进了全局环境右下角切换解释器到项目虚拟环境重新执行 pip install模拟考试计时不准前端本地时间被用户手动改过倒计时时间用服务端返回的开考时间计算前端只做展示错题本数据越来越多列表打开很慢查询没有分页且缺少关键索引给答案记录表添加(user_id, created_at)联合索引使用 Django 分页器npm install 报 ERESOLVE 错误依赖版本相互冲突升级 Node 到 LTS 版本或者用npm install --legacy-peer-deps避开校验这些问题的共同特点就是发生的时间点都在“项目跑起来了之后”这种时候最容易被忽略。我每次遇到都三连问服务日志有没有报错数据库连接正常吗前端网络请求有没有发出去按这个顺序排查百分之八十的问题能在五分钟内定位。4.3 部署与后续扩展建议部署这块两个后端服务我用了不同的方案。Django 用 gunicorn 加上多 worker 跑在生产环境Flask 同样用 gunicorn 独立起几个 worker两个服务前面都放一个 nginx 做反向代理同时接上 SSL 证书。前端 Vue 打包出来的静态文件直接交给 nginx 托管配置一个 location 指向dist目录就行。Django 的静态文件和媒体文件如果量不大也交给 nginx 直接托管避免每张题目的配图都穿过后端性能浪费。有个部署时的细节必须提一下Django 默认开启了 DEBUG 模式一上线就必须设为 False并且要配置 ALLOWED_HOSTS 列表。如果忘了你的 IP 地址会直接拒绝访问服务器日志里一堆 “Invalid HTTP_HOST header”。这类问题网上教程讲得少但几乎每个人都会撞一次。生产环境我强烈建议把数据库从 SQLite 迁移到 PostgreSQL不仅仅是并发性能的问题数据一致性、备份恢复的体验也完全不一样。后续扩展方向我简单说两个。第一个是数据分析模块可以根据用户的答题记录用 pandas 做题目难度分析和用户能力雷达图这部分正好可以补齐数据库统计接口前端用 ECharts 画图。第二个是结合 AI 做智能组卷根据用户的薄弱知识点自动生成个性化练习卷Django 后端留一个策略接口Flask 这边跑抽题算法扩展起来非常方便。我在实际开发到最后部署的过程中最大的体会是架构选择真的比写代码重要。项目开始前花半天把 Django 和 Flask 的边界划分清楚比后期从 Django 里硬拆服务出来省太多事。数据表设计多花一点时间想清楚后面写接口和前端都顺很多。如果你也想做一个类似的刷题系统我建议从题库模块开始入手先把“录入题目-展示题目-提交答案-记录错题”这条主线跑通再慢慢扩展模拟考试、成绩统计这些功能这样每一步都有成型的东西可以验证遇到问题也容易定位。
返回列表