一. 项目功能概述
本次项目使用Python语言编写的Flask框架下的web应用。主要用到的技术有MySQL、HTML前端以及Flask框架。该项目的主要功能有实现管理员的登录、学生信息的图表统计、学生信息的增删改查、学生成绩的增删改查、学生选课情况的修改与查询、学生奖惩情况的图表统计以及修改和删除、对已毕业学生的毕业去向进行图表统计。以上功能共有14个前端页面,后端封装成三个模块文件,同时在MySQL中共建有5张表格。
二.项目实现步骤
1.项目的搭建
本次项目的编码环境为Pycharm2021专业版,首先我们创建名为student_system的python项目,由于我们采用的是Flask框架,所以我们需要在Flask框架下新建static文件夹用来存储静态文件,新建templates文件夹用于存储HTML模板文件,具体结构如下图1所示。app.py文件是接口模块,用来连接前端页面。获取前端页面的数据或者将前端数据传送到后端,同时里面还定义了很多的动态路由以及与路由相关的视图函数。studentdata.py模块里定义了与数据库中表格相关联的类,类中定义了很多的方法用来对数据库进行增删改查。Functions.py模块主要用于定义创建studentdata.py模块的实例化对象并调用相应的方法。
图1 项目结构
接着我们来创建名为student的数据库,在库中创建5张表。students表为学生信息表,course表为学生选课表,direction表为已毕业学生的毕业去向表,grades表为学生的成绩表,rewards表为学生的奖惩情况表,各表中字段如图2所示。
图2 数据库表中各字段
2.登录功能及主页面的展示
在登录功能中,由于涉及到对数据进行增删改查,为了该管理系统的安全性,我们只允许学校的管理人员进行登录,非管理人员则无权登录。因此我们给定管理员用户名为“admin”,密码为“123456”。我们输入用户名和密码点击登录后,会跳转至主页面。同时在app.py模块中定义登录接口以及主页面接口,用以跳转页面。
functions.py
# 登录功能def login(): username = request.form.get('username') password = request.form.get('password') if username != 'admin': return '账号错误,请重新输入!' else: if password == '123456': session['username'] = username return 1 else: return "密码错误,请重新登录"
app.py
登录界面
主界面
3.图表展示功能
在图表展示功能以及毕业去向和奖惩情况页面,我们需要将从数据库获取到的数据进行图表展示的形式,直观的展现到前端页面。我们需要用到python中的第三方库pyecharts,我们打开cmd运行框输入pip install pyecharts进行下载。如我们需要展示各二级学院的人数,我们在studentdata.py模块中创建Student类,并初始化属性,定义查询二级学院的方法,并将结果以列表的形式返回。在functions.py模块中我们导入studentdata模块,定义各二级学院名字的列表depart_lst,遍历depart_lst进行批量创建实例化对象并调用查找二级学院的方法,将返回的列表的长度即为每个二级学院的人数存储到num_lst中。通过Bar函数来创建图表,x轴为depart-lst,y轴为num_lst,设置标题为“各学院学生人数”。最终调用dump_options()这个方法将图表绘制在网页中。不过该需要自己引入echarts.js文件,该js文件可以在相对应的网站进行打包下载。接着我们在app.py模块添加与前端页面相对应的路由,并配置视图函数,在视图函数中调用该方法,将图表传至前端页面,同时在前端页面中我们通过echarts函数将其展示到前端页面中。
charts.html界面
studentdata.py
# 查询各个学院的学生姓名 def search_department(self): # ping()使用该方法 ping(reconnect=True) ,那么可以在每次连接之前,会检查当前连接是否已关闭,如果连接关闭则会重新进行连接。 db.ping(reconnect=True) # 插入sql语句 sql = "SELECT name FROM students WHERE department='" + self.department + "'" # 执行sql语句 cursor.execute(sql) results1 = cursor.fetchall() results = [] for item in results1: results.append(item) # 关闭数据库 db.close() # 返回结果 return results
functions.py
# 图表展示各二级学院人数def char_department(): depart_lst = ['理学院', '计算机学院', '电子学院', '商学院', '海外教育学院', '地理学院'] num_lst = [] for item in depart_lst: student = std.Student('', '', '', '', '', f'{item}', '') num_lst.append(len(student.search_department())) bar = (Bar(init_opts=opts.InitOpts(bg_color='lightskyblue')).add_xaxis(depart_lst) .add_yaxis("人数", num_lst).set_global_opts(title_opts=opts.TitleOpts(title="各学院学生人数"))) bar_options = bar.dump_options() return bar_options
app.py
# 图表统计页面接口@app.route('/charts')def charts(): bar_options = func.char_department() pie_options = func.char_gender() bar_options1 = func.char_age() return render_template('charts.html', bar_options=bar_options, pie_options=pie_options, bar_options1=bar_options1)
charts.html
<div id="main1" style="width:100%;height: 300px"></div> <div id="main2" style="width:100%;height: 200px"></div> <div id="main3" style="width:100%;height: 300px"></div> <script type="text/javascript"> var mychart1=echarts.init(document.getElementById('main1'),'walden'); var mychart2=echarts.init(document.getElementById('main2')); var mychart3=echarts.init(document.getElementById('main3')); mychart1.setOption({{ bar_options|safe }}); mychart2.setOption({{ pie_options|safe }}); mychart3.setOption({{ bar_options1|safe }}); </script>
4.增删改查功能
该功能主要用于在学生成绩页面、学生信息页面、奖惩情况页面以及学生选课页面。如学生成绩页面有查询成绩、录入成绩、修改成绩以及删除成绩的功能。由于每个页面的功能都类似,我们仅以学生成绩界面加以说明。首先我们对成绩进行查询,在studentdata定义Grade类,定义输入学号查询成绩的方法,并以列表的形式返回,在functions模块中定义查询成绩的函数,并给定形参snum为学号,创建实例化对象并调用方法,将结果以列表的形式返回。在app.py模块中定义查询成绩的路由以及视图函数。在视图函数中去调用functions模块中的查询成绩的函数,并将前端输入框的学号作为实参,将列表传至前端页面。在前端页面中我们通过jinja2模板来对列表进行遍历,以表格的形式展示到前端页面中。
接着我们对成绩进行修改和删除,具体流程与上述查询成绩类似。我们先在studentdata.py模块中Grade类里定义修改和删除的方法,对数据操作时,修改会用到UPDATE语句而删除用到的是DELETE语句。在functions类中定义修改的函数,并添加形参snum,创建实例化对象,并将学号传入对象中,并调用方法。由于在app.py接口中还需要获取前端页面获取的值,为了接口模块的简洁,我们将获取前端的值一并写入functions中。最后在app模块中直接调用并传入实参即可。在删除学生成绩中,代码量比较少,我们直接在app.py模块接口中创建Grade的实例化,并传入实参调用删除学生成绩的方法即可。
最后我们对录入成绩进行实现,我们需要用到INSERT语句来将数据添加到数据库中。首先在前端页面中,我们以表格的形式将输入框展示到页面中。在studentdata.py模块中,我们在Grade类中定义录入成绩的方法,通过INSERT SQL语句将数据加入到数据库成绩表中。在这里我们需要注意的是pymysql在进行插入数据时,如果是varchar或string类型,需要使用Python中的repr()函数将对象转化为供解释器读取的形式。在function.py模块中我们定义录入成绩的函数,获取前端页面输入的值,创建实例化方法传入参数并调用方法。在HTTP中,常见的请求方法有GET和POST。GET请求中的参数包含在URL里面,数据可以在URL中看到,而POST的请求的URL不会包含这些数据;同时GET请求提交的数据最多只有1024字节,而POST方式没有限制。在app.py模块中我们定义录入成绩的视图函数,同时为了防止数据的泄露,我们在视图函数中判断请求的方法是GET请求还是POST请求,如果是GET请求,我们则展示页面,如果是POST请求,我们则调用录入成绩的函数,并将页面重定向至查询成绩界面。其他界面的增删改查与上述基本一致。
查询全部成绩
单个查询
录入成绩
删除成绩
studentdata.py
class Grade: def __init__(self, snum, course1, course2, course3, course4): self.snum = snum self.course1 = course1 self.course2 = course2 self.course3 = course3 self.course4 = course4 # 按学号查询学生的成绩 def search_snum_grade(self): # ping()使用该方法 ping(reconnect=True) ,那么可以在每次连接之前,会检查当前连接是否已关闭,如果连接关闭则会重新进行连接。 db.ping(reconnect=True) # 插入sql语句 sql = "SELECT * FROM grades WHERE snum='" + self.snum + "'" # 执行sql语句 cursor.execute(sql) results1 = cursor.fetchone() results = [] for item in results1: results.append(item) # 关闭数据库 db.close() # 返回结果 return results # 查询学生的成绩 def search_grade(self): db.ping(reconnect=True) # 插入sql语句 sql = "SELECT * FROM grades" # 执行sql语句 cursor.execute(sql) results1 = cursor.fetchall() results = [] for item in results1: results.append(list(item)) # 关闭数据库 db.close() # 返回结果 return results # 修改学生成绩 def update_grade(self): # ping()使用该方法 ping(reconnect=True) ,那么可以在每次连接之前,会检查当前连接是否已关闭,如果连接关闭则会重新进行连接。 db.ping(reconnect=True) # 插入sql语句 sql = "UPDATE grades SET course1='" + self.course1 + "',course2='" + self.course2 + "',course3='" + self.course3 + "', course4='" + self.course4 + "' WHERE snum='" + self.snum + "'" # 执行sql语句 cursor.execute(sql) db.commit() db.close() # 删除学生成绩 def delete_grade(self): # ping()使用该方法 ping(reconnect=True) db.ping(reconnect=True) sql = "DELETE FROM grades WHERE snum='" + self.snum + "' " cursor.execute(sql) # 提交到数据库执行 db.commit() # 关闭数据库 db.close() # 录入成绩 def add_grade(self): # ping()使用该方法 ping(reconnect=True) db.ping(reconnect=True) # 编写sql语句 sql_0 = "INSERT INTO grades(snum,course1,course2,course3,course4) VALUES(%s,%s,%s,%s,%s)" sql = sql_0 % (repr(self.snum), repr(self.course1), repr(self.course2), repr(self.course3), repr(self.course4)) cursor.execute(sql) # 提交到数据库执行 db.commit() # 关闭数据库 db.close()
functions.py
# 按学号查找单个学生的成绩def search_snum_grade(snum): grade_lst = [] grade_lst.append(std.Grade(snum, '', '', '', '').search_snum_grade()) return grade_lst# 查找全部学生的成绩def search_grade(): grade_lst = (std.Grade('', '', '', '', '').search_grade()) return grade_lst# 修改学生成绩def update_grade(snum): st = [] lst = ['course1', 'course2', 'course3', 'course4'] for item in lst: st.append(request.form.get(f'{item}')) std.Grade(snum, st[0], st[1], st[2], st[3]).update_grade()# 录入学生成绩def add_grade(): lst = ['snum', 'course1', 'course2', 'course3', 'course4'] grade_lst = [] for item in lst: grade_lst.append(request.form.get(f'{item}')) std.Grade(grade_lst[0], grade_lst[1], grade_lst[2], grade_lst[3], grade_lst[4]).add_grade()
app.py
# 学生成绩界面接口(按学号查)@app.route('/grade', methods=['GET', 'POST'])def grade(): if request.method == 'GET': return render_template('grade.html') if request.method == 'POST': grade_lst = func.search_snum_grade(request.form.get('snum')) return render_template('grade.html', grade_lst=grade_lst)# 全部学生成绩界面接口@app.route('/all-grade')def all_grade(): grade_lst1 = func.search_grade() return render_template('grade.html', grade_lst1=grade_lst1)# 修改学生成绩@app.route('/update-grade/<grade_list>', methods=['GET', 'POST'])def update_grade(grade_list): snum = grade_list[2:6] grade_list1 = func.search_snum_grade(snum) if request.method == 'GET': return render_template('update-grade.html', grade_list1=grade_list1, snum=snum) if request.method == 'POST': func.update_grade(snum) return redirect('/grade')# 删除学生成绩的接口@app.route('/delete-grade/<grade_list>')def delete_grade(grade_list): num = grade_list[2:6] std.Grade(num, '', '', '', '').delete_grade() return redirect('/grade')# 录入学生成绩的接口@app.route('/add-grade', methods=['GET', 'POST'])def add_grade(): if request.method == 'GET': return render_template('add-grade.html') if request.method == 'POST': func.add_grade() return redirect('/grade')
grade.html
<div id="content"> <div id="content-header"> <div id="breadcrumb"><a href="#" title="Go to Home" class="tip-bottom"><i class="icon-home"></i> Home</a> <a href="#" class="current">学生成绩录入及查询</a></div> </div> <div id="data3" style="width: 100%"> <form action="" method="post"> <label> <input style="height: 30px" type="text" name="snum" placeholder="输入学号查询成绩"/> <input type="submit" style="height: 30px" value="查询" href="/grade"> <a href="/all-grade" style="margin-left: 20px;color: #0e90d2">查询全部</a> <a href="/grade" style="margin-left: 30px;color: #0e90d2">返回单个查询</a> <a href="/add-grade" style="margin-left: 30px;color: #0e90d2">录入学生成绩</a> </label> </form> {% if grade_lst|length==1 %} <table style="width: 80%;margin-left: 88px;background:coral;"> <caption>学生成绩 共{{ grade_lst|length }}条记录</caption> <tr> <td style="width: 87px;text-align: center">学号</td> <td style="width: 87px;text-align: center">课程一</td> <td style="width: 87px;text-align: center">课程二</td> <td style="width: 87px;text-align: center">课程三</td> <td style="width: 87px;text-align: center">课程四</td> <td style="width: 87px;text-align: center">修改操作</td> <td style="width: 87px;text-align: center">删除操作</td> </tr> {% for item in grade_lst %} <tr> {% for items in item %} <td style="width: 87px;text-align: center">{{ items }}</td> {% endfor %} <td style="width: 87px;text-align: center"><a href="/update-grade/{{ item }}">修改</a> </td> <td style="width: 87px;text-align: center"><a href="/delete-grade/{{ item }}" onclick="delete_grade()">删除</a> </td> </tr> {% endfor %} </table> {% else %} <table style="width: 80%;margin-left: 88px;background: #5bc0de"> <caption>学生成绩 共{{ grade_lst1|length }}条记录</caption> <tr> <td style="width: 87px;text-align: center">学号</td> <td style="width: 87px;text-align: center">课程一</td> <td style="width: 87px;text-align: center">课程二</td> <td style="width: 87px;text-align: center">课程三</td> <td style="width: 87px;text-align: center">课程四</td> <td style="width: 87px;text-align: center">修改操作</td> <td style="width: 87px;text-align: center">删除操作</td> </tr> {% for item in grade_lst1 %} <tr> {% for items in item %} <td style="width: 87px;text-align: center">{{ items }}</td> {% endfor %} <td style="width: 87px;text-align: center"><a href="/update-grade/{{ item }}">修改</a> </td> <td style="width: 87px;text-align: center"><a href="/delete-grade/{{ item }}" onclick="delete_grade()">删除</a> </td> </tr> {% endfor %} </table> {% endif %} </div>
github源码地址: https://github.com/JBZ0805/student_system.git