跳到主要内容
Python Flask Web 开发实战:将本地学生成绩系统升级为在线应用 | 极客日志
Python 大前端
Python Flask Web 开发实战:将本地学生成绩系统升级为在线应用 使用 Flask 框架将本地 Python 学生成绩管理系统升级为在线 Web 应用。涵盖 Flask 安装、路由与模板基础、项目结构规范、Pandas 数据整合、Matplotlib 图表可视化嵌入以及表单交互查询功能。通过实战案例演示如何构建首页、列表页、报告页及搜索页,解决新手常见的路径错误、静态文件引用及请求方法问题,最终实现多人浏览器访问的完整系统。
狂少 发布于 2026/3/24 更新于 2026/5/23 14 浏览Python Flask Web 开发实战:将本地学生成绩系统升级为在线应用
之前的学生系统只能在自己电脑上运行,无法共享;数据和图表都存在本地文件,多人协作不方便。今天我们要学习 Python 的轻量级 Web 框架——Flask。它就像一座'桥梁',能把咱们之前写的本地学生成绩管理、数据可视化逻辑,快速升级为在线 Web 应用,让多人通过浏览器访问、查询成绩、查看可视化报告。
一、为什么选择 Flask?Web 开发的'入门钥匙'
在学具体操作前,先搞懂'为什么要做 Web 应用'和'为什么选 Flask':
本地项目的局限 :之前的学生系统只能在自己电脑上运行,无法共享;数据和图表都存在本地文件,多人协作不方便;
Web 应用的优势 :只要有浏览器(电脑、手机都可以),就能访问系统;数据集中存储,多人实时查看最新成绩;
Flask 的特点 :轻量级、易上手,不需要复杂配置,适合快速把本地项目升级为 Web 应用;支持整合 Pandas、Matplotlib 等库,完美衔接咱们的代码。
简单说:Flask 能以最低的学习成本,让你的本地工具变成'人人可用的在线服务'。
二、Flask 基础:从'Hello World'到 Web 服务
首先,咱们先搞定 Flask 的安装和核心概念,用几行代码跑通第一个 Web 服务,建立基础认知。
1. 安装 Flask 与依赖
Flask 是第三方库,需要先安装。另外,咱们还要用到 Pandas(处理数据)、Matplotlib(生成图表),所以一起安装:
pip install flask
pip install pandas matplotlib seaborn
安装完成后,验证是否成功:打开 Python 终端,输入 import flask,没有报错就说明安装成功。
2. 核心概念:Flask 的'三大件'
Flask 有三个核心概念,搞懂它们就能入门 Web 开发:
路由(Route) :URL 地址与 Python 函数的映射关系。比如访问 http://localhost:5000/(首页),对应执行 index() 函数;
视图函数(View Function) :处理路由请求的 Python 函数,负责逻辑计算(比如读取数据、生成图表),并返回响应(比如 HTML 页面、字符串);
模板(Template) :用于渲染 Web 页面的 HTML 文件,通过 Jinja2 模板引擎,能把 Python 变量(比如学生数据)动态插入到 HTML 中,让页面'活'起来。
3. 实战 1:跑通第一个 Flask 应用(Hello World)
创建一个名为 app.py 的文件(Flask 项目的主程序文件),写入以下代码:
from flask import Flask
app = Flask(__name__)
@app.route('/' )
def index ():
__name__ == :
app.run(debug= )
return
"<h1>欢迎访问学生成绩管理系统!</h1><p>这是用 Flask 开发的 Web 应用</p>"
if
'__main__'
True
运行步骤:
打开终端,进入 app.py 所在的文件夹;
执行命令 python app.py,看到以下输出:
* Serving Flask app 'app'
* Debug mode: on
* Running on http:
打开浏览器,访问 http://localhost:5000/,就能看到页面显示:
大标题'欢迎访问学生成绩管理系统!'
副标题'这是用 Flask 开发的 Web 应用'
关键说明:
调试模式 :debug=True非常重要,开发时开启,修改代码后不用手动重启服务;
URL 与路由 :@app.route('/')对应根 URL,如果你定义 @app.route('/student'),访问 http://localhost:5000/student 才会触发对应的视图函数;
响应内容 :目前返回的是简单 HTML 字符串,后面会用模板返回更复杂的页面。
三、Flask 进阶:整合学生数据与 Web 页面 单纯的字符串响应不够美观,也无法展示复杂的学生数据。接下来,咱们用模板 渲染 HTML 页面,把之前的学生 CSV 数据展示成 Web 表格,实现'本地数据→Web 表格'的跨越。
1. 项目结构:规范文件组织 随着功能增加,文件需要按规则存放,否则会混乱。创建以下项目结构(跟着手动建文件夹和文件):
student_web/ # 项目根文件夹
├── app.py # 主程序文件(Flask 核心逻辑)
├── students_data.csv # 学生数据文件(之前生成的)
├── templates/ # 存放 HTML 模板的文件夹
│ ├── base .html # 基础模板(所有页面继承这个)
│ ├── index.html # 首页
│ └── student_list.html # 学生列表页
└── static / # 存放静态文件(图片、CSS、JS)
└── images/ # 存放可视化图表的文件夹
2. 模板继承:减少重复 HTML 代码 Web 开发中,多个页面(如首页、学生列表页)会有相同的头部(导航栏)和底部(版权信息),用模板继承 可以避免重复写这些代码。
步骤 1:创建基础模板 templates/base.html
<!DOCTYPE html >
<html lang ="zh-CN" >
<head >
<meta charset ="UTF-8" >
<title > {% block title %}学生成绩管理系统{% endblock %}</title >
<link href ="https://cdn.jsdelivr.net/npm/[email protected] /dist/css/bootstrap.min.css" rel ="stylesheet" >
</head >
<body >
<nav class ="navbar navbar-expand-lg navbar-dark bg-primary" >
<div class ="container" >
<a class ="navbar-brand" href ="/" > 学生成绩系统</a >
<div class ="collapse navbar-collapse" >
<ul class ="navbar-nav" >
<li class ="nav-item" > <a class ="nav-link" href ="/" > 首页</a > </li >
<li class ="nav-item" > <a class ="nav-link" href ="/student/list" > 学生列表</a > </li >
<li class ="nav-item" > <a class ="nav-link" href ="/report" > 可视化报告</a > </li >
</ul >
</div >
</div >
</nav >
<div class ="container mt-4" > {% block content %}{% endblock %} </div >
<footer class ="mt-5 py-3 bg-light text-center" >
<div class ="container" >
<p class ="mb-0" > © 2024 学生成绩管理系统 | 用 Flask 开发</p >
</div >
</footer >
<script src ="https://cdn.jsdelivr.net/npm/[email protected] /dist/js/bootstrap.bundle.min.js" > </script >
</body >
</html >
模板继承说明:
{% block title %}:子页面可以替换这里的标题;
{% block content %}:子页面的核心内容放在这里;
引入 Bootstrap:这是一个免费的 CSS/JS 库,不用自己写样式就能让页面美观,新手友好。
3. 首页开发:templates/index.html 首页继承 base.html,展示系统简介和快速入口:
{% extends "base.html" %}
{% block title %}首页 - 学生成绩管理系统{% endblock %}
{% block content %}
<div class ="jumbotron bg-light p-5 rounded-3" >
<h1 class ="display-5 fw-bold" > 欢迎使用学生成绩管理系统</h1 >
<p class ="lead mt-3" > 本系统基于 Python Flask 开发,整合 Pandas 数据处理和 Matplotlib 可视化,支持以下功能:</p >
<ul class ="list-group list-group-flush mt-3 w-50" >
<li class ="list-group-item" > 查看所有学生的成绩列表</li >
<li class ="list-group-item" > 查询单个学生的详细成绩</li >
<li class ="list-group-item" > 查看各科成绩的可视化报告</li >
</ul >
<div class ="mt-4" >
<a href ="/student/list" class ="btn btn-primary me-3" > 进入学生列表</a >
<a href ="/report" class ="btn btn-success" > 查看可视化报告</a >
</div >
</div >
{% endblock %}
4. 学生列表页:展示 Pandas 处理的数据 接下来,在 app.py 中添加路由和视图函数,用 Pandas 读取 students_data.csv,传递到模板,渲染成 Web 表格。
步骤 1:修改 app.py,添加学生列表路由
import pandas as pd
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/' )
def index ():
return render_template('index.html' )
@app.route('/student/list' )
def student_list ():
df = pd.read_csv('students_data.csv' , encoding='utf-8' , dtype={'course_score' : int })
df['grade' ] = df['course_score' ].apply(lambda x: 'A 级 (90+)' if x >= 90 else ('B 级 (80-89)' if x >= 80 else 'C 级 (<80)' ))
student_data = df.to_dict('records' )
total_students = df['name' ].nunique()
total_courses = df['course_name' ].nunique()
return render_template('student_list.html' , students=student_data, total_students=total_students, total_courses=total_courses)
if __name__ == '__main__' :
app.run(debug=True )
步骤 2:创建学生列表模板 templates/student_list.html
{% extends "base.html" %}
{% block title %}学生列表 - 学生成绩管理系统{% endblock %}
{% block content %}
<div class ="d-flex justify-content-between align-items-center mb-4" >
<h2 > 学生成绩列表</h2 >
<p class ="text-muted" > 总学生数:{{ total_students }} 人 | 总课程数:{{ total_courses }} 门</p >
</div >
<table class ="table table-striped table-hover" >
<thead class ="table-dark" >
<tr >
<th > 学生姓名</th >
<th > 年龄</th >
<th > 课程名称</th >
<th > 成绩(分)</th >
<th > 成绩等级</th >
</tr >
</thead >
<tbody >
{% for student in students %}
<tr >
<td > {{ student.name }}</td >
<td > {{ student.age }}</td >
<td > {{ student.course_name }}</td >
<td > {{ student.course_score }}</td >
<td >
{% if student.grade == 'A 级 (90+)' %}
<span class ="badge bg-success" > {{ student.grade }}</span >
{% elif student.grade == 'B 级 (80-89)' %}
<span class ="badge bg-warning" > {{ student.grade }}</span >
{% else %}
<span class ="badge bg-danger" > {{ student.grade }}</span >
{% endif %}
</td >
</tr >
{% endfor %}
</tbody >
</table >
{% endblock %}
运行测试:
确保 students_data.csv 在项目根目录;
运行 app.py,访问 http://localhost:5000/student/list,就能看到:
顶部显示总学生数和课程数;
美观的表格,展示每个学生的姓名、年龄、课程、成绩;
成绩等级用不同颜色的标签显示(A 级绿色、B 级黄色、C 级红色)。
四、Flask + 可视化:Web 页面展示图表 上一篇咱们生成了柱状图、饼图,但只能存在本地文件。现在要让这些图表在 Web 页面展示,步骤是:
在 Flask 中生成图表,保存到 static/images/ 文件夹;
在模板中引用静态文件夹的图片路径,渲染到页面。
1. 修改 app.py,添加可视化报告路由
import matplotlib.pyplot as plt
import seaborn as sns
import os
plt.rcParams['font.sans-serif' ] = ['SimHei' , 'PingFang SC' ]
plt.rcParams['axes.unicode_minus' ] = False
sns.set_style("whitegrid" )
if not os.path.exists('static/images' ):
os.makedirs('static/images' )
@app.route('/report' )
def report ():
df = pd.read_csv('students_data.csv' , encoding='utf-8' , dtype={'course_score' : int })
df['grade' ] = df['course_score' ].apply(lambda x: 'A 级 (90+)' if x >= 90 else ('B 级 (80-89)' if x >= 80 else 'C 级 (<80)' ))
course_avg = df.groupby('course_name' )['course_score' ].mean().round (1 )
fig, ax = plt.subplots(figsize=(6 , 4 ), dpi=100 )
bars = ax.bar(course_avg.index, course_avg.values, color='skyblue' , edgecolor='black' )
ax.set_title('各科平均分对比' , fontsize=12 )
ax.set_xlabel('课程名称' )
ax.set_ylabel('平均分(分)' )
ax.set_ylim(80 , 90 )
for bar in bars:
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width() / 2 , height + 0.5 , str (height), ha='center' , va='bottom' )
plt.savefig('static/images/course_avg.png' , bbox_inches='tight' )
plt.close()
grade_count = df['grade' ].value_counts()
fig, ax = plt.subplots(figsize=(6 , 6 ), dpi=100 )
colors = ['#FF6B6B' , '#4ECDC4' , '#45B7D1' ]
wedges, texts, autotexts = ax.pie(
grade_count.values, labels=grade_count.index, autopct='%1.1f%%' , startangle=90 , colors=colors, explode=(0.05 , 0 , 0 ))
ax.set_title('成绩等级分布' , fontsize=12 )
for autotext in autotexts:
autotext.set_color('white' )
plt.savefig('static/images/grade_pie.png' , bbox_inches='tight' )
plt.close()
return render_template('report.html' )
2. 创建可视化报告模板 templates/report.html
{% extends "base.html" %}
{% block title %}可视化报告 - 学生成绩管理系统{% endblock %}
{% block content %}
<h2 > 学生成绩可视化报告</h2 >
<p class ="text-muted mb-4" > 基于学生成绩数据生成的图表分析</p >
<div class ="row g-4" >
<div class ="col-md-6" >
<div class ="card shadow-sm" >
<div class ="card-body" >
<h5 class ="card-title" > 各科平均分对比</h5 >
<img src ="{{ url_for('static', filename='images/course_avg.png') }}" alt ="各科平均分柱状图" class ="img-fluid" >
</div >
</div >
</div >
<div class ="col-md-6" >
<div class ="card shadow-sm" >
<div class ="card-body" >
<h5 class ="card-title" > 成绩等级分布</h5 >
<img src ="{{ url_for('static', filename='images/grade_pie.png') }}" alt ="成绩等级饼图" class ="img-fluid" >
</div >
</div >
</div >
</div >
{% endblock %}
关键说明:
url_for('static', filename='images/course_avg.png'):Flask 的辅助函数,自动生成静态文件的 URL,避免手动写路径出错;
img-fluid:Bootstrap 的类,让图片自适应页面宽度,在手机上也能正常显示;
card shadow-sm:给图表加卡片样式和阴影,让页面更有层次感。
运行测试: 访问 http://localhost:5000/report,就能看到两个图表在 Web 页面上展示,和之前本地生成的一样,但现在任何人都能通过浏览器访问。
五、交互功能:学生成绩查询 只展示还不够,还要支持'用户输入姓名,查询该学生的成绩'。这需要用到 Flask 的表单处理 ,接收用户输入的姓名,查询数据后返回结果。
1. 修改 app.py,添加查询路由
from flask import request
@app.route('/student/search' , methods=['GET' , 'POST' ] )
def student_search ():
if request.method == 'GET' :
return render_template('student_search.html' )
elif request.method == 'POST' :
student_name = request.form.get('student_name' , '' ).strip()
if not student_name:
return render_template('student_search.html' , error='请输入学生姓名!' )
df = pd.read_csv('students_data.csv' , encoding='utf-8' , dtype={'course_score' : int })
df['grade' ] = df['course_score' ].apply(lambda x: 'A 级 (90+)' if x >= 90 else ('B 级 (80-89)' if x >= 80 else 'C 级 (<80)' ))
student_df = df[df['name' ] == student_name]
if student_df.empty:
return render_template('student_search.html' , error=f'未找到名为' {student_name}'的学生' , input_name=student_name)
else :
student_data = student_df.to_dict('records' )
total_score = student_df['course_score' ].sum ()
avg_score = student_df['course_score' ].mean().round (1 )
return render_template('student_search.html' , student=student_data, total_score=total_score, avg_score=avg_score, input_name=student_name)
2. 创建查询模板 templates/student_search.html
{% extends "base.html" %}
{% block title %}学生查询 - 学生成绩管理系统{% endblock %}
{% block content %}
<div class ="row justify-content-center" >
<div class ="col-md-8" >
<h2 > 学生成绩查询</h2 >
<form method ="POST" class ="mt-4" >
<div class ="input-group mb-3" >
<input type ="text" name ="student_name" class ="form-control" placeholder ="请输入学生姓名(如:小明)" value ="{{ input_name if input_name else '' }}" >
<button class ="btn btn-primary" type ="submit" > 查询</button >
</div >
{% if error %}
<div class ="alert alert-danger" role ="alert" > {{ error }}</div >
{% endif %}
</form >
{% if student %}
<div class ="card mt-4" >
<div class ="card-header bg-primary text-white" >
<h5 class ="mb-0" > {{ input_name }} 的成绩详情 <span class ="float-end" > 总分:{{ total_score }} | 平均分:{{ avg_score }}</span > </h5 >
</div >
<div class ="card-body" >
<table class ="table table-sm mb-0" >
<thead >
<tr >
<th > 课程名称</th >
<th > 成绩(分)</th >
<th > 成绩等级</th >
</tr >
</thead >
<tbody >
{% for item in student %}
<tr >
<td > {{ item.course_name }}</td >
<td > {{ item.course_score }}</td >
<td >
{% if item.grade == 'A 级 (90+)' %}
<span class ="badge bg-success" > {{ item.grade }}</span >
{% elif item.grade == 'B 级 (80-89)' %}
<span class ="badge bg-warning" > {{ item.grade }}</span >
{% else %}
<span class ="badge bg-danger" > {{ item.grade }}</span >
{% endif %}
</td >
</tr >
{% endfor %}
</tbody >
</table >
</div >
</div >
{% endif %}
</div >
</div >
{% endblock %}
关键功能说明:
请求方法 :methods=['GET', 'POST']表示该路由支持两种请求:GET(访问页面)、POST(提交表单);
表单回显 :value="{{ input_name if input_name else '' }}"让用户查询失败时,输入框保留之前的内容,不用重新输入;
错误提示 :用 Bootstrap 的 alert-danger 类显示错误信息(如'未找到学生'),用户体验更好。
运行测试:
访问 http://localhost:5000/student/search;
输入'小明',点击查询,会显示小明的课程、成绩、总分和平均分;
输入'不存在的名字',会显示错误提示'未找到该学生'。
六、完整项目实战:在线学生成绩管理系统 现在,咱们的系统已经有了 4 个核心功能:首页、学生列表、可视化报告、成绩查询。最后,把导航栏和所有功能串联起来,确保用户能通过导航在各个页面间切换(之前的 base.html 已经做好了导航栏)。
最终项目结构回顾 student_web/
├── app.py # 主程序(路由、数据处理、图表生成)
├── students_data.csv # 学生数据(数据源)
├── templates/
│ ├── base .html # 基础模板(导航栏、底部)
│ ├── index.html # 首页(系统简介)
│ ├── student_list.html # 学生列表(所有成绩表格)
│ ├── student_search.html # 成绩查询(交互功能)
│ └── report.html # 可视化报告(图表展示)
└── static /
└── images/
├── course_avg.png # 柱状图(自动生成)
└── grade_pie.png # 饼图(自动生成)
运行完整系统的步骤
确保所有文件按上述结构存放;
安装所有依赖(flask、pandas、matplotlib、seaborn);
运行 python app.py,打开浏览器访问 http://localhost:5000/;
通过导航栏切换'首页→学生列表→成绩查询→可视化报告',测试所有功能。
七、常见问题:避坑指南 Flask 开发虽然简单,但新手容易在'路径''请求处理''静态文件'上踩坑,总结如下:
问题 1:模板路径错误(找不到 HTML 文件)
return render_template('studentlist.html' )
模板必须放在 templates 文件夹(名字不能错,全小写);
渲染时文件名必须和实际一致,包括下划线、大小写(Flask 区分大小写)。
问题 2:静态文件引用错误(图表不显示)
<img src ="static/images/course_avg.png" >
<img src ="{{ url_for('static', filename='images/course_avg.png') }}" >
问题 3:请求方法错误(表单提交没反应)
@app.route('/student/search' )
def student_search ():
if request.method == 'POST' :
pass
@app.route('/student/search' , methods=['GET' , 'POST' ] )
问题 4:数据读取路径错误(找不到 CSV 文件)
df = pd.read_csv('data/students_data.csv' )
确保 students_data.csv 在 app.py 所在的根目录;
或用绝对路径(不推荐,换电脑会失效):
import os
csv_path = os.path.join(os.path.dirname(__file__), 'students_data.csv' )
df = pd.read_csv(csv_path)
问题 5:调试模式关闭(修改代码不生效) 注意 :生产环境(给别人正式使用时)要关闭 debug=True,否则有安全风险。
八、小结与下一篇预告
这篇你学到了什么?
Flask 基础 :理解路由、视图函数、模板的核心概念,跑通 Web 服务;
模板开发 :用 Jinja2 模板继承减少重复代码,引入 Bootstrap 美化页面;
数据整合 :把 Pandas 本地数据处理逻辑迁移到 Flask,渲染成 Web 表格;
可视化 Web 化 :在 Flask 中生成图表,保存到静态文件夹,在页面展示;
交互功能 :用 request 处理表单提交,实现学生成绩查询,提升用户体验;
项目实战 :构建完整的在线学生成绩管理系统,掌握 Web 项目的文件结构和开发流程。
下一篇预告 今天的 Flask 应用已经能通过浏览器访问,但数据还是存在本地 CSV 文件中,多人同时修改会冲突,而且无法持久化存储新数据(比如新增学生)。下一篇咱们会学 Python 的数据库操作,用 SQLite(轻量级数据库,无需安装)替换 CSV 文件,实现数据的增删改查,让 Web 应用真正支持多人协作,成为生产级别的系统。
相关免费在线工具 curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online