news 2026/9/19 13:38:24

学生选课成绩分析系统实战:Flask+Vue+ECharts前后端分离开发

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
学生选课成绩分析系统实战:Flask+Vue+ECharts前后端分离开发

做学生选课成绩分析这个系统,我踩了不少坑,也攒了不少可以直接抄作业的方案。这个项目从标题看涉及 Flask、Vue、Django、PyCharm 一整套东西,但本质上就是一个典型的前后端分离 Web 应用,核心是做学生选课、成绩管理,再把成绩数据做成可视化图表。今天我把这套系统的完整思路、关键代码、踩坑记录全部整理出来,希望能帮你少走弯路。

这套东西适合谁看?正在做课程设计的学生、刚接触 Flask 想练手完整项目的开发者、以及想给学校或培训机构做内部成绩分析系统的人。项目不算特别复杂,但麻雀虽小五脏俱全,足够把 Python Web 开发、前端框架、数据可视化、数据库设计这些点全部串起来。

1. 项目整体设计与技术选型思路

1.1 技术栈为什么这么选:两个 Python 框架怎么分工

标题里同时出现了 Flask 和 Django,很多人会疑惑到底用哪个。我的建议是:核心业务逻辑用 Flask,别把 Django 硬塞进来。Django 自带 Admin 后台、ORM、认证体系,开发效率确实高,但正因为内置东西太多,学习成本反而高,而且对学生项目来说有点“重”。Flask 轻量、灵活,路由自己写,ORM 用 SQLAlchemy 自己配,代码结构完全可控,更适合做这种需要展示完整开发过程的项目。

那 Vue 和 Django 出现在标题里是什么情况?我的理解是:Vue 是前端框架,负责页面交互和数据可视化展示;Django 可以作为“备选方案”或者你在对比调研时涉及过。实际开发中我不建议一个项目里同时用 Flask 和 Django,服务端架构反而变乱。

1.2 整体架构:按前后端分离的标准来搭

这套系统的整体结构是这样的:

  • 后端:Flask 提供 RESTful API,负责学生管理、课程管理、选课逻辑、成绩录入和成绩分析计算
  • 前端:Vue 2 + Element UI 搭建管理界面,ECharts 渲染可视化图表
  • 数据库:MySQL 存储业务数据,SQLAlchemy 做 ORM
  • 开发工具:PyCharm 写 Python 后端,VSCode 或 WebStorm 写 Vue 前端

前后端分离的好处是职责清晰,后端只返回 JSON 数据,前端只管页面渲染和交互。考试系统、选课系统这类项目,评审老师或答辩评委往往更看重架构的规范性,这算是加分项。

1.3 功能模块拆解:一个成绩系统要拆成几块

把需求拆成模块:

  • 学生模块:学生信息的增删改查、导入导出
  • 课程模块:课程信息管理、授课教师信息
  • 选课模块:学生选课、退课、选课名单查看
  • 成绩模块:成绩录入、修改、成绩单查询
  • 分析模块:班级平均分、课程通过率、成绩分布、分数段统计
  • 可视化模块:ECharts 柱状图、饼图、折线图展示分析结果

这种拆分方式是所有管理系统的基础套路,做完这个项目,换任何业务场景都能套用这套结构。

2. 数据模型设计与核心接口实现

2.1 数据库表设计:三张核心表和一张关联表

数据库我用 MySQL,建库语句:

CREATE DATABASE student_course CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

核心表设计如下:

学生表(student)

字段类型说明
idINT 主键自增学生ID
student_noVARCHAR(20) 唯一学号
nameVARCHAR(50)姓名
genderVARCHAR(10)性别
class_nameVARCHAR(50)班级
enrollment_yearINT入学年份

课程表(course)

字段类型说明
idINT 主键自增课程ID
course_noVARCHAR(20) 唯一课程编号
course_nameVARCHAR(100)课程名称
creditFLOAT学分
teacherVARCHAR(50)授课教师

成绩表(score)

字段类型说明
idINT 主键自增成绩ID
student_idINT 外键关联学生
course_idINT 外键关联课程
scoreFLOAT成绩
semesterVARCHAR(20)学期

这里有个关键点:成绩表的设计决定后续分析的灵活度。我见过有人把成绩字段直接冗余到选课表里,这样也能实现,但后期做统计分析时逻辑会绕很多。单独建 score 表,每个学生每门课一条记录,统计分析时 group by 课程、group by 班级都很方便。

2.2 Flask-SQLAlchemy 模型定义

新建 models.py,核心代码:

from flask_sqlalchemy import SQLAlchemy from datetime import datetime db = SQLAlchemy() class Student(db.Model): __tablename__ = 'student' id = db.Column(db.Integer, primary_key=True, autoincrement=True) student_no = db.Column(db.String(20), unique=True, nullable=False) name = db.Column(db.String(50), nullable=False) gender = db.Column(db.String(10)) class_name = db.Column(db.String(50)) enrollment_year = db.Column(db.Integer) created_at = db.Column(db.DateTime, default=datetime.now) scores = db.relationship('Score', backref='student', lazy='dynamic') def to_dict(self): return { 'id': self.id, 'student_no': self.student_no, 'name': self.name, 'gender': self.gender, 'class_name': self.class_name, 'enrollment_year': self.enrollment_year } class Course(db.Model): __tablename__ = 'course' id = db.Column(db.Integer, primary_key=True, autoincrement=True) course_no = db.Column(db.String(20), unique=True, nullable=False) course_name = db.Column(db.String(100), nullable=False) credit = db.Column(db.Float, default=0) teacher = db.Column(db.String(50)) scores = db.relationship('Score', backref='course', lazy='dynamic') def to_dict(self): return { 'id': self.id, 'course_no': self.course_no, 'course_name': self.course_name, 'credit': self.credit, 'teacher': self.teacher } class Score(db.Model): __tablename__ = 'score' id = db.Column(db.Integer, primary_key=True, autoincrement=True) student_id = db.Column(db.Integer, db.ForeignKey('student.id'), nullable=False) course_id = db.Column(db.Integer, db.ForeignKey('course.id'), nullable=False) score = db.Column(db.Float, nullable=False) semester = db.Column(db.String(20)) created_at = db.Column(db.DateTime, default=datetime.now) def to_dict(self): return { 'id': self.id, 'student_id': self.student_id, 'student_name': self.student.name if self.student else '', 'course_id': self.course_id, 'course_name': self.course.course_name if self.course else '', 'score': self.score, 'semester': self.semester }

to_dict 方法非常重要,因为 Flask 的 jsonify 不能直接序列化 SQLAlchemy 的模型对象。每次写接口都要转 dict,这个方法是 Python 后端开发的基础功。

2.3 核心 API 接口设计

在 app.py 中,路由定义如下:

from flask import Flask, request, jsonify from models import db, Student, Course, Score app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:password@localhost/student_course' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db.init_app(app) @app.route('/api/students', methods=['GET']) def get_students(): """获取学生列表,支持按姓名和班级搜索""" keyword = request.args.get('keyword', '') query = Student.query if keyword: query = query.filter(db.or_( Student.name.like(f'%{keyword}%'), Student.student_no.like(f'%{keyword}%') )) students = query.all() return jsonify({'code': 0, 'data': [s.to_dict() for s in students]}) @app.route('/api/students', methods=['POST']) def add_student(): """新增学生""" data = request.get_json() student = Student( student_no=data.get('student_no'), name=data.get('name'), gender=data.get('gender', ''), class_name=data.get('class_name', ''), enrollment_year=data.get('enrollment_year', 2024) ) db.session.add(student) db.session.commit() return jsonify({'code': 0, 'data': student.to_dict()}) @app.route('/api/courses', methods=['GET']) def get_courses(): courses = Course.query.all() return jsonify({'code': 0, 'data': [c.to_dict() for c in courses]}) @app.route('/api/scores', methods=['POST']) def add_score(): """录入成绩,注意检查该学生是否已选该课程""" data = request.get_json() student_id = data.get('student_id') course_id = data.get('course_id') score_value = data.get('score') # 检查学生是否选了这门课 if not is_enrolled(student_id, course_id): return jsonify({'code': 1, 'msg': '该学生未选择此课程,无法录入成绩'}), 400 score = Score( student_id=student_id, course_id=course_id, score=score_value, semester=data.get('semester', '2024-2025-1') ) db.session.add(score) db.session.commit() return jsonify({'code': 0, 'data': score.to_dict()})

这里录入成绩时检查是否选课这个逻辑,很多人会漏掉。不检查的话,就会出现没选课却有成绩的数据,导致后续分析结果不准。这是从业务逻辑层面就要卡住的点。

3. 成绩分析算法与可视化实现

3.1 成绩分析的核心维度

可视化不是把成绩表搬到网页上,而是通过图表直接看出问题。我做了四个核心分析维度:

维度一:班级平均分对比。按班级分组,计算每门课程的平均分,用柱状图对比。这能直观看出哪个班级在某门课程上明显落后,背后可能是教学问题或生源差异。

维度二:课程成绩分布。将一门课的成绩按优秀(90-100)、良好(80-89)、中等(70-79)、及格(60-69)、不及格(0-59)五个区间统计人数,用饼图展示。这个分布能快速判断试卷难度是否合理,优秀率和不及格率的比例是否符合预期。

维度三:成绩趋势分析。同一个学生或同一个班级的成绩是上升还是下降,通过折线图呈现。比如某学生大一到大三的加权平均分变化,可以辅助辅导员做学业预警。

维度四:课程通过率排名。统计每门课程的通过率,用横向柱状图排序。通过率最低的课程需要重点关注,可能是教学难度设置有问题。

3.2 后端统计分析接口的实现

以成绩分布为例,Flask 端代码:

@app.route('/api/analysis/distribution/<int:course_id>', methods=['GET']) def get_score_distribution(course_id): """统计指定课程的成绩分布""" scores = Score.query.filter_by(course_id=course_id).all() distribution = { 'excellent': 0, # 90-100 'good': 0, # 80-89 'medium': 0, # 70-79 'pass': 0, # 60-69 'fail': 0 # 0-59 } for s in scores: if s.score >= 90: distribution['excellent'] += 1 elif s.score >= 80: distribution['good'] += 1 elif s.score >= 70: distribution['medium'] += 1 elif s.score >= 60: distribution['pass'] += 1 else: distribution['fail'] += 1 total = len(scores) if total > 0: for key in distribution: distribution[key] = round(distribution[key] / total * 100, 2) course = Course.query.get(course_id) return jsonify({ 'code': 0, 'data': { 'course_name': course.course_name if course else '', 'distribution': distribution } })

这个接口返回的是百分比,不是人数。前端拿百分比直接画饼图,不用重复计算,前后端的职责更清晰。

计算完成后要学会用 SQL 验证,开发阶段我经常在 Navicat 里手动跑一遍 SQL 对比接口数据,确保代码逻辑没写错:

SELECT SUM(CASE WHEN score >= 90 THEN 1 ELSE 0 END) / COUNT(*) * 100 AS excellent_pct, SUM(CASE WHEN score >= 80 AND score < 90 THEN 1 ELSE 0 END) / COUNT(*) * 100 AS good_pct, SUM(CASE WHEN score >= 70 AND score < 80 THEN 1 ELSE 0 END) / COUNT(*) * 100 AS medium_pct, SUM(CASE WHEN score >= 60 AND score < 70 THEN 1 ELSE 0 END) / COUNT(*) * 100 AS pass_pct, SUM(CASE WHEN score < 60 THEN 1 ELSE 0 END) / COUNT(*) * 100 AS fail_pct FROM score WHERE course_id = 1;

3.3 前端 Vue + ECharts 可视化展示

前端我用 Vue 2 + Element UI + ECharts。安装依赖:

npm install vue@2 npm install element-ui npm install echarts

vue.config.js 里配置开发环境代理,解决跨域问题:

module.exports = { devServer: { proxy: { '/api': { target: 'http://127.0.0.1:5000', changeOrigin: true } } } }

在 ScoreAnalysis.vue 组件中,成绩分布饼图这样实现:

<template> <div class="analysis-container"> <el-card> <div slot="header"> <span>课程成绩分布分析</span> </div> <el-select v-model="selectedCourse" placeholder="请选择课程" @change="loadDistribution"> <el-option v-for="course in courses" :key="course.id" :label="course.course_name" :value="course.id"> </el-option> </el-select> <div ref="distributionChart" class="chart"></div> </el-card> </div> </template> <script> import * as echarts from 'echarts' import request from '@/utils/request' export default { name: 'ScoreAnalysis', data() { return { selectedCourse: null, courses: [], distributionChart: null } }, mounted() { this.loadCourses() }, methods: { loadCourses() { request.get('/api/courses').then(res => { this.courses = res.data }) }, loadDistribution(courseId) { request.get(`/api/analysis/distribution/${courseId}`).then(res => { const data = res.data this.renderPieChart(data.distribution) }) }, renderPieChart(distribution) { if (this.distributionChart) { this.distributionChart.dispose() } this.distributionChart = echarts.init(this.$refs.distributionChart) const labels = ['优秀(90-100)', '良好(80-89)', '中等(70-79)', '及格(60-69)', '不及格(<60)'] const values = [ distribution.excellent, distribution.good, distribution.medium, distribution.pass, distribution.fail ] const option = { title: { text: '成绩分布饼图(百分比)', left: 'center' }, tooltip: { trigger: 'item', formatter: '{b}: {c}%' }, legend: { orient: 'vertical', left: 'left' }, series: [{ name: '成绩分布', type: 'pie', radius: '55%', center: ['50%', '60%'], data: labels.map((label, index) => ({ name: label, value: values[index] })), emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } } }] } this.distributionChart.setOption(option) } }, beforeDestroy() { if (this.distributionChart) { this.distributionChart.dispose() } } } </script> <style scoped> .chart { width: 100%; height: 400px; margin-top: 20px; } </style>

注意 beforeDestroy 里一定要 dispose 图表实例,否则路由切换后 ECharts 实例不会自动销毁,内存泄漏不说,还会导致图表重绘报错警告。

4. 开发环境与工具链配置

4.1 PyCharm 环境搭建

PyCharm 是 Python 后端最重要的 IDE,安装后第一件事是配置解释器和创建虚拟环境。

打开 PyCharm,Settings → Project → Python Interpreter → 设置齿轮 → Add → Virtualenv Environment → New environment。虚拟环境一定要建在项目目录下,这样换电脑项目迁移时能直接重建。

禁用系统 Python 环境是个重要习惯。如果把第三方库装进系统 Python,不同项目之间权限完全混乱,A 项目要 Django 3.2,B 项目要 Django 4.2,就会相互冲突。虚拟环境隔离了每个项目的依赖。

然后安装后端依赖:

pip install flask pip install flask-sqlalchemy pip install flask-cors pip install pymysql pip install pandas pip install flask-restful

flask-cors 是必须装的,否则前端跨域请求会被浏览器拦截。也可以在 Flask 端这样配:

from flask_cors import CORS CORS(app)

4.2 Vue 前端环境配置

前端侧,Node.js 环境我建议 LTS 版本,使用 nvm 管理 Node 版本,切换版本比手动安装方便得多。

# 全局安装 Vue CLI npm install -g @vue/cli # 创建前端项目 vue create student-analysis-web # 进入项目目录 cd student-analysis-web # 安装依赖 npm install

在 PyCharm 里也可以直接打开 vue.config.js 改写端口配置,后端 Flask 跑在 5000 端口,前端 Vue 跑在 8080 端口,通过 devServer proxy 请求后端接口,去掉跨域限制。

4.3 启动前后端服务的顺序

整个开发环境启动流程:

  1. 启动 MySQL 服务,确认 3306 端口正常监听
  2. 用 PyCharm 打开后端项目,运行 app.py,Flask 开发服务器跑在 5000 端口
  3. 用终端进入前端项目目录,执行 npm run serve,Vue 跑在 8080 端口
  4. 浏览器访问 http://localhost:8080

遇到启动失败不要慌,多半是端口被占用。用命令行查端口:

netstat -ano | findstr :5000

把占用进程杀掉,或者改 Flask 的启动端口:

if __name__ == '__main__': app.run(debug=True, port=5001)

5. 数据初始化与完整项目联调

5.1 测试数据怎么造:手动录不如脚本插

真实开发中不可能靠页面一条条录数据,我写了个 Python 脚本批量生成模拟数据,这样测试可视化效果才有足够的数据样本:

import random from app import app from models import db, Student, Course, Score def init_data(): with app.app_context(): # 先清空旧数据 db.session.query(Score).delete() db.session.query(Student).delete() db.session.query(Course).delete() # 生成学生 classes = ['计算机2101', '计算机2102', '软件2101'] students = [] for i in range(90): s = Student( student_no=f'2021{1000+i}', name=f'学生{i+1}', gender=random.choice(['男', '女']), class_name=random.choice(classes), enrollment_year=2021 ) db.session.add(s) students.append(s) db.session.commit() # 生成课程 courses_data = [ ('C001', 'Python程序设计', 3, '张老师'), ('C002', '数据结构', 4, '李老师'), ('C003', '数据库原理', 3.5, '王老师'), ('C004', '操作系统', 4, '赵老师'), ('C005', '计算机网络', 3, '孙老师') ] courses = [] for no, name, credit, teacher in courses_data: c = Course(course_no=no, course_name=name, credit=credit, teacher=teacher) db.session.add(c) courses.append(c) db.session.commit() # 随机生成选课和成绩 for student in students: # 每个学生选修 3-5 门课 selected_courses = random.sample(courses, random.randint(3, 5)) for course in selected_courses: score_value = random.randint(45, 100) sc = Score( student_id=student.id, course_id=course.id, score=score_value, semester='2023-2024-1' ) db.session.add(sc) db.session.commit() print('初始化完成') if __name__ == '__main__': init_data()

这段脚本我故意让成绩分布在 45 到 100 之间,就会有少量不及格记录,饼图渲染时各个分数段都有数据,展示效果好。全部 90 分以上会显得假,全是高分在真实教学场景中几乎不可能。

5.2 整体联调的关键检查点

联调阶段,我整理了一个检查清单:

  • 学生列表能否正常按班级筛选,姓名搜索是否准确匹配
  • 新增学生后,页面列表能否立即刷新
  • 录入成绩时,未选课的学生是否会被正确拦截
  • 修改成绩后,分析页面的图表数据是否同步更新
  • 删除学生时,该学生的选课和成绩记录是否级联处理干净

最后一个删除学生的级联问题很隐蔽。我一开始删学生时报外键约束错误,原因是 score 表里还有该学生的成绩记录。解决办法有两种,一是在删除接口中手动先删关联成绩,二是在数据库外键上设置 ON DELETE CASCADE。新手建议用第一种,逻辑透明可控。

删除接口改成这样:

@app.route('/api/students/<int:student_id>', methods=['DELETE']) def delete_student(student_id): student = Student.query.get(student_id) if not student: return jsonify({'code': 1, 'msg': '学生不存在'}), 404 # 先删除关联成绩 Score.query.filter_by(student_id=student_id).delete() db.session.delete(student) db.session.commit() return jsonify({'code': 0, 'data': '删除成功'})

5.3 部署时的线程与高并发问题

开发环境里 Flask 自带的开发服务器是单进程的,性能有限。到了需要部署给多人用的阶段,不要直接python app.py上线。生产环境推荐用 gunicorn(Linux 下)或 waitress(Windows 下)作为 WSGI 服务器:

pip install waitress waitress-serve --host=0.0.0.0 --port=5000 app:app

这时候就容易碰到 SQLAlchemy 的线程问题。开发模式单线程没事,多线程并发时会出现“SQLite objects created in a thread can only be used in that same thread”之类的报错,解决方法是给数据库连接池加上合适的配置,或者确保 session 按请求创建和销毁。Flask-SQLAlchemy 本身做了请求上下文管理,但多线程部署时仍建议检查:

app.config['SQLALCHEMY_ENGINE_OPTIONS'] = { 'pool_size': 10, 'pool_recycle': 3600, 'pool_pre_ping': True }

6. 常见问题与排查技巧实录

6.1 跨域请求被拦截:浏览器 Console 报错怎么办

现象:前端页面能打开,但请求后端接口时报 CORS error,或者 Network 面板里请求状态是 failed。

排查思路:首先是确认后端有没有开启 CORS 支持。在 Flask 里最简单的做法:

from flask_cors import CORS CORS(app, resources={r"/api/*": {"origins": "*"}})

其次是检查前端代理是否配置正确。开发环境推荐用 devServer proxy,而不是在后端开全局 CORS,这样生产环境前端的 API 路径不用改。

6.2 中文乱码:页面显示问号或华文乱码

现象:MySQL 里的中文显示正常,但页面显示问号;或者页面正常,数据库里全是问号。

排查思路:这是编码问题,分三段查。第一,数据库连接串要加 charset:

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:password@localhost/student_course?charset=utf8mb4'

第二,MySQL 建库时指定 charset,这一步我在前面建库语句里就写好了。第三,Python 文件本身要保存为 UTF-8 编码,PyCharm 默认是 UTF-8,但如果你用记事本改过,文件头建议加# -*- coding: utf-8 -*-兜底。

6.3 ECharts 图表不显示:页面空白但数据有返回

现象:接口返回的数据正常,但图表区域空白,控制台没有报错。

排查思路:这是初始化时机问题。ECharts 初始化时必须保证 DOM 已经渲染完成,如果在数据加载之前图表 DIV 还没计算好宽高,init 时拿到的是 0 或 undefined,图表就画不出来。解决办法有两种:

一是在 mounted 里用this.$nextTick等待 DOM 渲染完成:

this.$nextTick(() => { this.distributionChart = echarts.init(this.$refs.distributionChart) })

二是 window 的 resize 事件触发后,手动调用 chart.resize() 让图表重新计算宽高:

window.addEventListener('resize', () => { if (this.distributionChart) { this.distributionChart.resize() } })

6.4 Flask debug 模式自动重启导致的数据库连接池耗尽

现象:开着 debug=True,修改代码后服务自动重启,跑一段时间后 MySQL 报 Too many connections。

排查思路:debug 模式的 reloader 会启动两个进程,父进程和子进程都持有数据库连接。开发环境一般不设连接池上限,但生产环境必须关掉 debug,并配置 pool_size 和 pool_recycle。我在生产部署时是彻底关 debug:

if __name__ == '__main__': app.run(debug=False, host='0.0.0.0', port=5000)

6.5 PyCharm 终端执行 pip install 报错

现象:PyCharm 终端执行 pip install flask 时,报 Microsoft Visual C++ 14.0 is required,或者 pip 找不到。

这个报错多见于 Windows 环境,某些 Python 包需要 C++ 编译环境,比如 mysqlclient、bcrypt 这类依赖。解决办法有两个:一是换成纯 Python 实现的替代包,比如 PyMySQL 替代 MySQLdb;二是安装 Microsoft C++ Build Tools。对课程设计项目,直接用 PyMySQL 是最省事的,驱动类型在连接串里指定 pymysql 就能避开编译问题。

6.6 前端调用接口一直是 404

现象:后端接口用 Postman 测没问题,前端页面上请求就变 404。

排查思路:检查 vue.config.js 的 proxy 是否配对了 prefix。比如后端接口是/api/students,前端请求如果写成了/students,代理就匹配不上,会直接把请求发给 Vue dev server 自己,自然 404。解决方法是保持前后端路径一致,统一从/api开头。

7. 项目扩展方向:从课程设计到简历亮点

这个系统做完,如果你想让它在面试或答辩中更有亮点,我建议往几个方向扩展:

方向一:引入数据分析深化场景。现在只是最基础的统计汇总,可以用 pandas 和 scikit-learn 做更深入的学业预警分析,比如根据历次成绩预测学生期末是否可能挂科、哪些因素对成绩影响最大。这一步能把项目从“管理系统”拔高到“分析系统”。

方向二:权限体系升级。目前前端只是简单页面展示,可以接入 Flask-Login 做登录认证,把学生、教师、管理员三个角色分开。学生只能看自己的成绩和选课情况,教师能录入和查看所授课程成绩,管理员有全部权限。这个工作量和面试加分都很可观。

方向三:导出报表功能。用 Flask 生成 Excel 报表是比较高频的需求,可以前端下载 xlsx 文件或者后端生成 CSV 供批量导入导出。我的实践是用 pandas 的 to_excel 生成 xlsx,和 openpyxl 一起配合。

方向四:性能与部署优化。用 Nginx 反向代理前端静态文件,后端用 gunicorn 或 waitress 多 worker 跑,再把 Flask 的 debug 彻底关掉,配上 HTTPS。这套部署方案,很多实际工作的初级开发都不一定全程做过。

做这个项目过程中,我最大的体会是:一个看起来“只是增删改查”的管理系统,真正把它拆开揉碎去实现,涉及到的知识点远比表面上多。数据库设计要提前考虑统计分析的需求,接口粒度要兼顾前端展示,可视化不是画个饼图那么简单,得结合业务解释数据意义。这套系统的所有源码和表结构我都已经跑通验证过,可以直接作为课程设计或毕业设计的参考,也可以在此基础上加功能、换技术栈,扩展成更适合你自己业务的版本。

最后分享一个实操小技巧:在开发阶段,把 Flask 的 JSON 返回格式统一成{code: 0, data: ..., msg: ...},前端封一个 request 工具类,所有接口统一处理这个格式,后续加功能、排错都会很爽。这个习惯我一直沿用到现在,比每个接口各写各的返回结构省心太多了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 13:38:15

VS Code报错Could not register service worker?精准清理与排查指南

1. 这个报错到底卡在哪一环VS Code 里弹出“加载Web视图时出错: Error: Could not register service worker: InvalidStateError”&#xff0c;第一反应往往是重启编辑器&#xff0c;但重启十次有九次还是老样子。这个报错的核心不在 VS Code 主进程&#xff0c;而在它内嵌的El…

作者头像 李华
网站建设 2026/9/19 13:37:58

Centos7安装Mysql5.7(超详细版)

文章目录一、下载mysql5.7的安装包①、选择linux版的②、选择64bit&#xff0c;根据自己的情况来看③、选择下载tar包④、点击下载⑤、等待下载完二、上传到服务器三、检查服务器是否安装过mysql服务四、卸载Centos7自带的mariadb①、查找系统自带的mariadb②、卸载系统自带的m…

作者头像 李华
网站建设 2026/9/19 13:34:28

Postman中文工作流搭建指南:稳定、协作友好的API测试方案

1. 这不是“装个中文包”那么简单&#xff1a;Postman 汉化背后的真实需求与认知误区 你搜“Postman汉化”&#xff0c;点开一堆教程&#xff0c;第一步就是让你下载某个“汉化补丁”或“中文版安装包”。我试过不下二十种所谓“一键汉化”的方案&#xff0c;有七成在启动时直…

作者头像 李华
网站建设 2026/9/19 13:33:18

U-Net医学图像分割:从架构原理到PyTorch实战与调参避坑指南

医学图像分割这个领域&#xff0c;U-Net 是一个绕不开的名字。2015 年它被提出的时候&#xff0c;本来是为了解决生物医学图像里标注数据少、分割边界模糊的问题&#xff0c;结果这套编码器-解码器加跳跃连接的结构后来在遥感、工业质检、甚至生成模型里都遍地开花。我最早接触…

作者头像 李华
网站建设 2026/9/19 13:32:23

DeepSeek智算一体机:智慧城管AI落地部署全指南

简介&#xff1a;智慧城管数字化场景下&#xff0c;面向智慧城市和城管信息化领域的产品经理、方案架构师与项目决策者&#xff0c;提供一份基于DeepSeek大模型的智算一体机设计方案演示文档&#xff0c;重点解决城市管理中的数据孤岛、人工巡检成本高、违规事件识别精度不足等…

作者头像 李华
网站建设 2026/9/19 13:31:17

Ubuntu 下 Anaconda 安装与 conda init 避坑指南

1. 为什么 Ubuntu 下装 Anaconda 这件事值得单独写一篇在 Ubuntu 上装 Anaconda&#xff0c;表面上看就是下载一个.sh文件、跑一条命令、一路回车的事。但我见过太多人卡在几个非常具体的地方&#xff1a;装完之后终端前面多了一个(base)&#xff0c;每次开终端都自动激活&…

作者头像 李华