
每年公考报名季高校就业指导中心的老师和我聊得最多的一个词就是“信息太散了”。国考、省考、事业单位、人才引进公告撒在几十个官方渠道里学生要么错过报名时间要么把备考资料存得到处都是。我自己在带毕设时也发现如果能做一个把招考资讯、辅导课程、政策通知整合在一起的平台不管是做毕业设计还是真正给学院用都非常有价值。今天要聊的这套源码就是干这个事的Python Flask 写后端接口Vue 写前端页面数据库用 MySQL开发环境是基于 PyCharm 搭建的功能上覆盖了资讯发布、公告管理、辅导资源展示、后台管理等常见模块。这套项目源码的标题里同时挂着 flask 和 django 两个关键词实际看了目录结构之后发现主体是 Flask 工程附带了一个 Django 风格的管理模块作为对照参考。打包资源的人为了让搜索命中率高把两个框架的名字都写进去了这也正常。如果你正准备找毕设项目或者想用 Flask Vue 完整练一遍前后端分离开发这个项目可以当主线参考。下面我按实际开发顺序从需求拆解到环境搭建、接口实现、上线部署把整套源码里值得关注的地方都说一遍。1. 项目整体需求拆解与功能规划1.1 这个系统到底在解决什么问题高校毕业生在准备公职考试时信息获取路径非常零散。招录公告要看政府官网岗位表要下 Excel备考资料散落在公众号和网盘辅导课程又分布在各个机构平台上学生要同时维护十几个入口很容易漏掉关键时间节点。这套系统的核心逻辑是把“公职资讯聚合 辅导资源管理”放在一个平台里。用户登录后可以看到按分类整理的招考资讯可以浏览辅导课程和公开课可以下载备考资料还能收藏自己感兴趣的内容。管理员在后台维护分类、发文、管理课程和用户整个信息流转比手工整理要高效得多。从源码的目录结构来看作者采用了典型的前后端分离方式后端提供 JSON 接口前端通过 HTTP 请求来消费接口数据。这种设计的好处是前后端可以并行开发后端调整不影响前端页面以后不管换 Web 端还是做小程序接口可以直接复用。1.2 源码里的功能模块清单把项目跑起来之后可以看到功能模块划分得比较清晰。我整理了一个功能表方便对照源码理解模块分类使用角色核心功能用户端学生、毕业生注册登录、个人资料、资讯浏览、公告通知、辅导课程浏览、资料下载、收藏管理端管理员资讯分类管理、资讯发布与编辑、公告管理、课程管理、用户管理、数据统计系统基础公共部分图片上传、JWT 登录鉴权、分页搜索、异常处理这些功能看起来不复杂但实际编码时涉及路由规划、权限校验、文件上传、跨域处理、数据库关联查询等问题。比如资讯列表不仅要分页还要支持按分类筛选、按标题模糊搜索、按置顶状态排序这条链路任何一个环节没打通前端页面显示就会出错。1.3 为什么选这个功能组合做这类项目最容易犯的错是功能堆砌。很多毕设源码上来就是购物车、订单、支付和业务场景完全脱节。这套源码明显是克制了只保留了资讯系统和辅导系统最核心的部分。从用户使用路径来看一个学生来到平台第一件事是看最新政策公告和招考资讯然后根据岗位信息去查对应备考资料再决定要不要参加辅导课程。资讯、课程、资料、收藏四个模块刚好串起这条链路。管理端做的事情则是保证内容能持续更新没有管理员维护的资讯平台上线一周就会变成死站。这个功能组合也决定了技术实现的复杂度比较适中既没有避开数据库设计和前后端交互又没有刻意去碰分布式、消息队列这些和业务不匹配的东西。对拿来做毕业设计或者学习范例来说是很好的度。2. 技术栈选型思考Flask、Vue 与 Django 怎么搭配2.1 Flask 赢在“轻”Django 赢在“全”很多人在选 Python Web 框架时都会纠结 Flask 还是 Django。我的看法是项目规模和团队习惯决定选型。Django 自带 Admin 后台、ORM、表单处理、认证体系项目骨架非常完整适合开发大型业务系统但它的工程结构和模块耦合也相对重初学者想完全搞明白并不容易。Flask 则是一个微内核框架核心只提供请求路由和模板渲染数据库、登录、表单全都可以按需加载。这个系统需要的就是一套轻量接口服务和灵活的数据模型用 Flask 后代码结构一目了然app.py 负责启动models.py 管数据表routes 目录管不同业务的路由。开发和调试都比 Django 直接。当然Django 也不是没有参考价值。这套源码里附带的 Django 模块演示了如何用 MTV 模式下自带 Admin 快速生成后台管理页相当于给了一个对照组。我在实际开发中的选择是如果后台管理页面要求不高直接用 Django Admin 能省掉大量 CRUD 编码如果要自定义各种业务细节Flask Flask-Admin 或者完全手写管理页反而更灵活。2.2 前端为什么用 Vue前端技术栈选择 Vue 是挺顺理成章的事。Vue 的核心优势是组件化和响应式数据绑定页面上的资讯列表、分页器、导航栏都能拆成独立组件复用性很好。和 Flask 后端之间通过 JSON 数据交换完全不依赖服务端模板Vue 和 Flask 的开发可以同时推进。从上手难度来说Vue 比 React 更接近传统 HTML 的书写习惯。一个资讯列表页面模板里写 v-for 循环渲染数据脚本里调用 axios 拉接口不需要理解复杂的状态管理概念。项目源码里用到的组件和路由配置也比较常规没有刻意上 Vuex 或者 Pinia这套模式很适合拿来学习。另外Vue 的构建工具在最新版本里已经切换到了 Vite启动速度快很多。如果你下载的源码还是老版本的 Vue CLI 配置我也想多说一句不要把时间花在纠结版本上核心原理是一样的都是组件 路由 HTTP 请求。2.3 开发工具链PyCharm 配合整个流程后端开发在 PyCharm 里进行是最顺手的。PyCharm 对 Flask 项目有原生支持可以一键创建 Flask 项目模板自带虚拟环境管理运行配置还能自动识别 app.py 入口。写代码时对 Flask 路由模版的补全、断点调试、SQL 语句提示都比通用编辑器要智能很多。版本选择上社区版是免费的日常写 Flask 完全够用专业版多了数据库工具、前端代码检查等功能学生可以申请教育免费授权。我不建议去碰网上那些激活脚本一来安全隐患很大二来你为省一点订阅费把自己电脑暴露风险完全不划算。老老实实装个社区版或者走正规授权项目一样能跑得飞起。环境还需要 MySQL 和 Node.js。MySQL 用来存数据Node.js 是运行前端开发服务器和打包工具的基础。Windows 下安装 MySQL 有一点要特别注意安装时记住 root 密码如果用 MySQL 8.x还可能在导入 sql 文件时遇到认证插件兼容问题后面我会专门讲。3. 数据库设计、后端接口与前端页面如何打通3.1 数据表结构是整套系统的地基拿到源码不要急着跑先看数据库设计脚本或者直接打开 models.py。这个系统的表结构设计得很典型我挑几张核心表来说明。用户表 user 字段包括 id、username、password_hash、phone、avatar、role、create_time。这里密码字段用的是 hash 值而不是明文虽然代码里可能只演示了注册功能但这个习惯必须养成。明文密码存数据库一旦泄露就是安全事故。资讯相关的表有两张category 和 article。category 是分类表里面有 id、name、sortarticle 是资讯主表字段有 id、category_id、title、cover、summary、content、source、views、is_top、publish_time。把分类和文章拆成两张表是为了避免在一张表里反复写一串相同的分类名后续想统计某类职位资讯的数量也会很方便。辅导相关的表包括 course、course_category 等course 表设计时把 video_url、file_url、teacher、intro 都放进去这样前端展示课程卡片时只需要一次查询就能拿到全部展示信息。还有一张 favorite 收藏表用 target_type 字段来区分收藏的是资讯还是课程这是一种很常见的“多态关联”写法可以省去为每种业务单独建一张收藏表的麻烦。3.2 用 Flask 写一个资讯列表接口后端代码最核心的一段是资讯查询接口。我简化一下源码里的写法大致是这样from flask import Blueprint, request, jsonify from models import Article, db from sqlalchemy import or_ article_bp Blueprint(article, __name__) article_bp.route(/api/articles, methods[GET]) def get_articles(): # 接收查询参数 page request.args.get(page, 1, typeint) limit request.args.get(limit, 10, typeint) keyword request.args.get(keyword, , typestr) category_id request.args.get(category_id, 0, typeint) # 构建查询条件 query Article.query if keyword: query query.filter(or_(Article.title.like(f%{keyword}%), Article.summary.like(f%{keyword}%))) if category_id: query query.filter(Article.category_id category_id) # 排序与分页 pagination query.order_by(Article.is_top.desc(), Article.publish_time.desc()) \ .paginate(pagepage, per_pagelimit, error_outFalse) # 组装返回结果 items [] for item in pagination.items: items.append({ id: item.id, title: item.title, cover: item.cover, summary: item.summary, category_id: item.category_id, views: item.views, publish_time: item.publish_time.strftime(%Y-%m-%d %H:%M:%S) }) return jsonify({ code: 0, data: items, total: pagination.total, page: page, limit: limit })这里有几个细节值得注意。分页用 SQLAlchemy 的 paginate 方法来处理比自己手算 offset 更安全还能顺带拿到 total 总数返回给前端渲染分页条。排序时用 is_top 字段做降序再按 publish_time 降序这样置顶文章始终在列表前面。关键字搜索用 LIKE 匹配标题和摘要虽然大数据量下性能一般但对这套系统来说完全够用。接口返回格式统一用 code data total 的结构前端拿到后直接判断 code 是否为 0不需要再包一层 try catch 去猜后端返回格式联调时可以省掉很多沟通成本。3.3 前端 Vue 如何消费后端接口Vue 端拿到这样的接口处理起来很直接。我以资讯列表页为例核心流程是页面加载时调用 axios 请求 /api/articles把返回的 items 数组渲染到模板里表格下方放分页组件请求参数里带上 page 和 limit。import axios from axios export default { data() { return { articleList: [], total: 0, page: 1, limit: 10 } }, created() { this.loadArticles() }, methods: { async loadArticles() { const res await axios.get(/api/articles, { params: { page: this.page, limit: this.limit, keyword: this.keyword, category_id: this.categoryId } }) if (res.data.code 0) { this.articleList res.data.data this.total res.data.total } } } }模板里用 v-for 循环渲染 articleList分页组件绑定 page 和 total切换页码时重新调用 loadArticles。这一步只要能打开浏览器看到数据就说明前后端已经打通了。开发阶段还有一个避不开的问题Flask 默认跑在 5000 端口Vue 开发服务器跑在 5173 或 8080 端口两者不同源浏览器会拦截跨域请求。解决方式有两种第一种是在 Flask 端加 flask-cors 放行所有域名适合快速联调第二种是在 Vue 的 vite.config.js 里配置 devServer.proxy把 /api 开头的请求代理到后端地址生产环境再由 Nginx 统一转发。我建议正式项目用第二种因为代理方式更贴近真实部署环境。4. 从 0 到 1 在 PyCharm 里跑通这套源码4.1 环境准备Python、MySQL、Node.js 一个都不能少先把底座搭好。Python 建议装 3.8 以上版本我自己测试时用的是 3.10Flask 2.x 和 SQLAlchemy 都能正常工作。安装时 Windows 系统要记得勾选 Add Python to PATH否则命令行里敲 python 会提示找不到命令。PyCharm 安装好之后直接选择 Open 打开下载的源码目录PyCharm 会自动识别到 requirements.txt并提示创建虚拟环境点确定即可。如果提示没有识别到项目类型建议检查一下项目根目录下是否有 app.py 或 wsgi.pyFlask 项目入口在那个位置。MySQL 安装时5.7 和 8.0 我都试过建议用 8.0功能更新而且字符集支持更好。安装过程中设置一个你能记住的 root 密码后续连接数据库需要用到。安装完成后用 Navicat 或命令行建一个名为 gongzhi 的数据库再把源码里的 gongzhi.sql 文件导入表结构就有了。Node.js 安装则比较简单一路默认即可。安装完成后打开终端输入 node -v 和 npm -v能输出版本号就算成功。4.2 后端启动步骤与数据库配置后端项目在 PyCharm 里打开后先确认虚拟环境已经激活。然后打开终端安装依赖cd backend python -m venv venv venv\Scripts\activate pip install -r requirements.txt如果没有 requirements.txt也可以手动安装pip install flask flask-sqlalchemy flask-cors pymysql flask-migrate flask-jwt-extended。安装完依赖后修改 config.py 里的数据库连接信息。常见的连接串写法是SQLALCHEMY_DATABASE_URI mysqlpymysql://root:yourpassword127.0.0.1:3306/gongzhi?charsetutf8mb4这里的 yourpassword 换成你本机 MySQL 的 root 密码。如果连的是远程数据库把 127.0.0.1 换成对应 IP。设置完成后运行 app.py控制台会输出 Running on http://127.0.0.1:5000说明后端服务起来了。一个容易踩的坑是MySQL 8.0 默认认证插件是 caching_sha2_password而旧版 PyMySQL 可能不支持。解决办法是把数据库用户认证插件改成 mysql_native_password或者在配置里装上最新版 PyMySQL一般后者就够了。4.3 前端项目启动与跨域代理配置前端目录一般叫 frontend 或 vue-front进入目录后cd frontend npm install npm run devnpm install 时间较长这期间可以先配置跨域代理不然等接口联调时再回头改又要浪费几分钟。vite 配置文件里加一段 server.proxyserver: { proxy: { /api: { target: http://127.0.0.1:5000, changeOrigin: true } } }如果你的源码是 Vue CLI 项目则在 vue.config.js 里配置 devServer.proxy原理一样。配置好后重启 npm run dev页面里就能直接请求后端接口了。前端默认开发端口常见的是 5173浏览器打开后如果页面白屏先看终端有没有报错。大多数情况是依赖没装完整或者 Node 版本太低建议 Node 不要低于 16。4.4 依赖安装常见报错速查我把源码运行过程中最常见的几个依赖问题整理成一个速查表遇到直接照着做报错信息原因解决办法ModuleNotFoundError: No module named MySQLdb用了 MySQLdb 但没装pip install pymysql并在 app 中添加 import pymysql; pymysql.install_as_MySQLdb()pip 安装超时访问官方源太慢换镜像pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simplenpm ERR! code ERESOLVE依赖版本冲突npm install --legacy-peer-depsnode-sass 安装失败老项目中 node-sass 和 Node 版本不兼容用 sass 替代或升级 Node 后再试No module named flask_wtf缺少表单扩展pip install flask-wtf这里特别提一下 pymysql 替换 mysqlclient 的方法很多源码写的是 import MySQLdb因为这个接口是从 mysqlclient 来的。装上 PyMySQL 后只要在项目入口文件加两行代码就可以兼容运行。这招在 Windows 上尤其好用因为 mysqlclient 在 Windows 下编译经常失败。5. 上线部署本地能跑只是第一步5.1 Flask 应用生产部署Waitress Nginx开发环境下python app.py 启动的是 Werkzeug 自带的开发服务器它有自动重载和调试页面但并发能力很差生产环境绝对不能直接用到公网。Windows 服务器上最常见的组合是 Waitress Nginx。Waitress 是纯粹的 Python WSGI 服务器安装和启动都很简单pip install waitress waitress-serve --host 0.0.0.0 --port 8000 app:app注意 app:app 前面是 Python 文件名后面是 Flask 实例名如果入口文件是 run.py并且里面的应用变量叫 application那就写成 run:application。启动后后端就监听在 8000 端口。Nginx 负责接收外部请求把静态资源直接返回把带 /api 的请求转发给 Waitress同时处理 Vue 打包后的前端文件。一个简单的配置片段server { listen 80; server_name your_domain.com; root /var/www/gongzhi_frontend/dist; index index.html; location /api/ { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location / { try_files $uri $uri/ /index.html; } }这段配置里 try_files 是 Vue history 路由必须的。前端路由切到 /article/1浏览器刷新时请求到服务端Nginx 找不到这个物理路径就直接返回 index.html再由 Vue 路由接管页面否则刷新就是 404。5.2 Vue 打包后的两个大坑Vue 开发模式一切正常npm run build 打出来的包放到服务器上却经常出问题。第一个坑是静态资源路径不对默认的 base 是反斜杠根路径如果你把前端放在域名子目录下就得在 vite.config.js 里设置 base: ./让资源路径变成相对路径或者部署时单独配置。第二个坑正好对应很多人在搜的“vue 打包后布局异常”。这类问题大多是两种原因一是本地调试时用了某个全局样式或 Element UI 组件但打包后 CSS 被压缩产生了覆盖问题二是路由跳转后页面容器高度塌陷导致底部留白或板块错位。排查时先用开发者工具看盒模型再看样式来源通常能定位到是某个全局样式没有加载进来。还有一点部署后 API 地址如果是写死的 http://127.0.0.1:5000那生产环境一定调不通。源码里一般会把 API 地址抽成一个环境变量或配置文件打包时要改成实际域名对应的 Nginx 地址。5.3 数据备份与迁移线上系统跑起来以后备份就是你最不能省的事。Flask 项目开发阶段可以用 Flask-Migrate 管理表结构变更流程是flask db init flask db migrate -m init tables flask db upgrade上线之后每天凌晨用 mysqldump 做一次全量备份是基本操作mysqldump -uroot -p --default-character-setutf8mb4 gongzhi /backup/gongzhi_$(date %Y%m%d).sql恢复时执行 mysql -uroot -p gongzhi backup.sql。这套操作我在实际项目里踩过坑一开始没加 --default-character-set 参数备份文件里中文注释全部乱码恢复后数据看起来像一堆问号。所以备份命令里的字符集参数千万别省略。6. 常见报错与排坑实录6.1 前后端联调被跨域卡住Flask 后端和 Vue 前端端口不同浏览器控制台报错 Access-Control-Allow-Origin missing第一反应就是跨域。如果你不想在前端做代理直接在 Flask 里加 flask-cors 是最省事的from flask_cors import CORS CORS(app)这样所有的接口都会带上跨域响应头开发环境没问题。但上线后建议只开放指定域名避免接口被任意第三方页面乱调用。写法是 CORS(app, resources{r/api/*: {origins: http://yourdomain.com}})。我遇到过一次很有意思的情况加了 CORS 还是报跨域。查了半天发现是浏览器端用了自定义请求头 x-token触发了预检请求而预检请求被 Flask 的某些路由拦掉了。最后在 CORS 配置里明确支持所有请求头才解决如果你的接口需要自定义 header记得也把 allow_headers 配好。6.2 中文乱码从数据库到前端层层排查中文乱码问题在 Flask Vue 项目里出现概率很高。排查顺序是先看数据库里的原始数据是否正常再用命令行请求 API 看返回内容最后检查浏览器渲染。数据库插入前要保证建库时指定了 utf8mb4 字符集连接串里也带 charsetutf8mb4。如果数据已经变成问号写进表里了基本没法修复只能删掉重来。返回 JSON 时Flask 的 jsonify 默认会把中文转成 Unicode 编码这不是乱码。如果不想让前端看到转义序列可以在 Flask 配置里设置 JSON_AS_ASCIIFalse。前端页面如果显示乱码检查 index.html 有没有设置以及 JS 文件是否正确加载。前后端编码全部统一成 UTF-8 之后这类问题基本灭绝。6.3 后台管理插件怎么选热搜词里出现的“flask 后台管理插件”指的大概率是 Flask-Admin。这个插件可以在几分钟内生成一套可用的后台管理界面只需要定义好你的模型类然后注册进去from flask_admin import Admin from flask_admin.contrib.sqla import ModelView admin Admin(app, name公职资讯后台) admin.add_view(ModelView(Article, db.session))它能自动生成列表、新增、编辑、删除页面对于纯管理表数据的需求开箱即用。但它的硬伤是对自定义页面支持很弱比如你想做一个富文本编辑器加一个图片上传组件或者自定义统计图表Flask-Admin 就有点吃力了。这套源码里的后台是自己写的前后端分离实现前台 Vue 管理页面后端写接口灵活性更高。我的建议是如果你赶时间可以用 Flask-Admin 先顶一段时间如果你要把它当毕设展示自己写管理页面更能体现完整度。6.4 看到 Django 词条别被带偏源码描述词里出现了 django但主工程里并没有用 Django。很多资源站为了在搜索时覆盖更多关键词会把同一类框架的名字都挂上去这并不代表代码里都用了。不过这里可以顺便说一下 Django 的 MTV 模式。M 是 Model负责数据表映射T 是 Template负责页面展示V 是 View负责业务逻辑。和 Flask 相比Django 把这三个层次直接内置到框架里开发时“约定优于配置”的味道更重。如果你先学了 Flask 再看 Django会觉得它的目录结构非常规整但代价是很多环节 Django 已经帮你做完了决策个性化时会觉得不够自由。实际选型时如果项目规模不大团队又熟悉 Flask完全没必要为了“大而全”硬上 Django。这套源码把两者放在一起更多是给学习者提供一个对照参考。6.5 开发环境里的其他小坑有朋友安装完 PyCharm 后 Flask 项目跑不起来第一反应是代码有问题其实很多时候是运行配置里的入口脚本选错了。PyCharm 里 Add Configuration选择 Flask ServerTarget 指向 app.py环境变量里设置 FLASK_ENVdevelopment就能正常启动。如果你在命令行里启动没问题在 PyCharm 里启动报错优先看虚拟环境和工作目录配置。还有一点虚拟环境一定要在项目目录里。很多时候 import flask 报 ModuleNotFoundError但命令行里明明已经装过依赖就是因为 PyCharm 解释器指向了全局环境而不是项目下的 venv。修改位置在 File - Settings - Project - Python Interpreter手动选到 venv 下的 python.exe 即可。整套源码我前后改了三版才觉得逻辑比较顺过程中最深的体会是前后端分离的项目真正耗时间的不是写代码而是把数据模型、接口约定、页面状态之间对接清楚。建议拿到源码后不要急着跑先把数据库表结构和接口文档过一遍能少踩很多坑。后续想扩展的话可以在资讯模块加上关键词检索和按专业分类的个性化推荐把辅导课程按直播、录播、题库拆成更细的资源类型再给管理员加一个简单的数据看板。这个项目底子打得不错扩展空间很大。