一、开发环境的安装与配置

1.1 Python3.10以及PyCharm的安装

浏览器输入Python官方网址:https://www.python.org/,点击下载进入下载界面,选择相对应的版本,本项目采用的是win64位的Python3.10版本。安装PyCharm步骤与上述一致,仅网址不同,本项目采用的是Pycharm2021专业版。

1.2MySQL8.0的安装

MySQL的安装与上述如出一辙,在浏览器地址栏输入MySQL官方网址,进入下载界面,选择相对应版本。本次项目采用的是win64位的MySQL8.0版本。

二.设计任务及理解

2.1设计任务

本项目的任务是基于flask模拟雨课堂教学系统的实现,前端页面的设计需参考雨课堂的界面,设计实现课程班级模块中的“我听的课”功能,能够创建课程信息,并提交。设计实现资源库中上传课件的功能,并显示课程上传时间,以及右上角数量汇总信息,同时可以实现删除的效果。

2.2 理解

对于本次项目,我对设计任务的理解的内容有:首先是本项目要基于flask框架,其次就是前端的页面,即使设计任务里没有提及到关于用户登录和注册的功能,为了设计的严谨性,这一功能是要添加上的;紧接着就是实现主页中的功能,可以连接MySQL,在MySQL中创建数据库,并与后端相连,再将数据传入前端页面中,可将用户名和班级信息进行绑定,从而达到设计的严谨性。

三、所用第三方库简介

3.1 Flask框架简介及所需要的库

Flask是一个非常轻量级的框架,提供了搭建Web服务的必要组件,Flask具有良好的扩展性,可以使用其他开源的Flask扩展插件。Flask框架里主要包含Jinja2模板引擎、路由、视图、静态文件和蓝图等。在本次项目中用到的有render_template、request、session、redirect、Jinja2模板引擎、路由、视图以及静态文件。

3.2 pymysql库

pymysql是在pycharm上使用的第三方包,在安装pymysql之前,首先必须要确保电脑上安装了MySQL。pymysql是作为MySQL客户端来操作数据,它的操作流程如图1所示。

图1 pymysql操作流程

四、设计方案与实现

4.1 项目结构

本次软件设计我们的项目结构如图2所示,static文件夹分别存放CSS文件、JS文件、图片以及上传的课件。templates文件夹存放模块文件,模板即在Flask中允许响应给用户看的网页,Flask中的模板是依赖于Jinja2的模板系统。默认情况下,Flask会在程序文件夹中的templates的子文件夹中搜索模板,我们需要手动创建templates文件夹。本次项目中,templates中共有4个模板文件,用于登录界面、注册界面、主界面以及上传界面的展示。app.py文件为后端的接口,里面配置了视图函数和路由。userdata.py文件为业务逻辑模块,用于连接数据库以及编写了相对应的方法。

图2 项目结构图

4.2 userdata.py与app.py设计方案

userdata模块中我们定义了三个类。User类(父类)主要用于用户的登录和注册,并将注册的数据保存到数据库中,以及查询用户所在的班级;Course_class类(子类)主要用于查询同一班级下的班级成员以及用户加入班级;Course类(子类)主要用于查询用户听的可以及添加课程。app.py模块中,我们主要定义了7个接口即视图函数,具体如图3所示,每个视图函数还会配置对应的路由。同时为了保护用户的隐私安全,我们还在该模块中设置了秘钥,否则将会抛出异常。

图3 app.py视图函数

4.3 数据库的设计

在本次项目中,我们新建了用于存储用户数据的数据库“yeketang”,该数据库如下图4所示,图中有三张表分别为user用户表、class班级表、以及course用户课程表。user表中有username、password字段;class表中有username、classid字段;course表中有username、courseid、coursename字段。

图4 数据库搭建

4.4 登录和注册的功能实现

接下来我们对登录和注册功能的实现,首先如图5所示为userdata模块下的User类中的登录和注册的流程图。在登录login()方法中,我们通过执行SQL语句来实现此功能。我们在用fetchone()函数获取数据库读取到的结果,返回的数据类型为元组类型,随后添加if条件语句,判断用户输入的密码是否在这个元组中,如果在元组中则返回1。如图6所示为app接口模块下的登录注册流程图。在HTTP中,常见的请求方法有GET和POST。GET请求中的参数包含在URL里面,数据可以在URL中看到,而POST的请求的URL不会包含这些数据;同时GET请求提交的数据最多只有1024字节,而POST方式没有限制。因此为了防止用户输入的密码泄露,我们在login()接口中,我们添加了if条件语句进行判断,如果是GET方法,我们就展示页面;如果是POST方法,就通过request.form.get()函数获取到前端页面输入的值,接着创建实例化对象并调用登录login()方法,流程如图8所示。最后我们添加一个if条件判断语句,判断login()方法返回的值是否为1,如果为1则说明登录成功,我们便将页面重定向至index主界面,否则就返回“账号密码错误,请重新登录”。对于注册功能的实现,与上述登录功能基本类似。首先在接口模块中先判断HTTP的请求方法。GET方法就展示页面,在POST方法下,获取到前端注册页面的username、password,接着创建实例化对象,并将username、password传入对象中,再调用register()方法执行SQL语句,将username、password存入数据库中,最后再将页面重定向至登录界面。

图5 userdata模块登录注册流程图

图6 app模块登录注册流程

userdata.py

# 定义用户类class User:    def __init__(self, username, password):        self.username = username        self.password = password    # 登录账号    def login(self):        # ping()使用该方法 ping(reconnect=True) ,那么可以在每次连接之前,会检查当前连接是否已关闭,如果连接关闭则会重新进行连接。        db.ping(reconnect=True)        # 编写sql语句,用来查询前端输入的用户名与数据库中user表对应的密码        sql = "select password from user where username='" + self.username + "'"        # 执行sql语句        cursor.execute(sql)        # 将数据从数据库读出 类型为元组类型        results = cursor.fetchone()        # 判断前端输入的密码是否与数据库密码一致,一致则返回1        if self.password in results:            return 1        # 关闭数据库        db.close()    # 注册账号    def register(self):        # ping()使用该方法 ping(reconnect=True) ,那么可以在每次连接之前,会检查当前连接是否已关闭,如果连接关闭则会重新进行连接。        db.ping(reconnect=True)        # 插入sql语句        sql_0 = "INSERT INTO user(username,password) VALUES(%s,%s)"        sql = sql_0 % (repr(self.username), repr(self.password))        # 执行sql语句        cursor.execute(sql)        # 提交到数据库执行        db.commit()        # 关闭数据库        db.close()

app.py

# 登录接口@app.route('/login', methods=['GET', 'POST'])def login():    if request.method == 'GET':        return render_template('login.html')    if request.method == 'POST':        username = request.form.get('username')  # 接收来自前台的账号        password = request.form.get('password')  # 接收来自前台的密码        user = ud.User(username, password)        logins = user.login()        if logins == 1:            # 将用户名存储至用户会话中,用户会话是一种私有存储,默认情况下,会保存在cookie中。            session['username'] = username            return redirect('/index')        else:            return '账户密码错误,请重新登录'# 注册接口@app.route('/register', methods=['GET', 'POST'])def register():    # 判断是get请求还是post请求    if request.method == 'GET':        return render_template('register.html')    if request.method == 'POST':        username = request.form.get('username')        password = request.form.get('password')        user = ud.User(username, password)        user.register()        return redirect('/login')

4.5 展示用户班级及班级成员功能的实现

接着我们对展示用户班级及班级成员的功能进行实现,具体流程如图7所示。首先我们需要通过用户会话来获取到用户在登录界面输入的用户名,调用show_user()方法时,还需要判断用户是否已经加入班级,定义一个变量results用于接收查询到的结果。如果数据库查不到记录,我们将results赋值为None,并返回results;反之我们将查询到的记录赋值给results并转为字符串,将结果返回,展示班级成员的方法与上述类似,这里就不展开说明了。最后在主接口中,判断返回的结果是否为None,是则添加班级,否则展示。接着再将后端数据传入前端数据。同时我们前端页面运用Jinja2模板进行判断,根据结果是否为None,展示不同的内容。

图7 用户班级流程图

userdata.py

# 查询用户所在班级的方法    def show_user(self):        # ping()使用该方法 ping(reconnect=True) ,那么可以在每次连接之前,会检查当前连接是否已关闭,如果连接关闭则会重新进行连接。        db.ping(reconnect=True)        # 插入sql语句        sql = "SELECT classid FROM class WHERE username='" + self.username + "'"        #执行sql语句,对该用户在class表中没有记录抛出异常,并将返回的结果赋值为None        try:            # 执行sql语句            cursor.execute(sql)            # 将数据从数据库读出 类型为元组类型 转成字符串            results = ''.join(cursor.fetchone())            #关闭数据库            db.close()            return results        except:            results=None            db.close()            return results# 定义课程班级类 班级类继承用户类class Course_class(User):    def __init__(self, username, password, class_id):        super().__init__(username, password)        self.class_id = class_id    # 查询用户所在的班级成员的方法    def show_class_member(self):        # ping()使用该方法 ping(reconnect=True) ,那么可以在每次连接之前,会检查当前连接是否已关闭,如果连接关闭则会重新进行连接。        db.ping(reconnect=True)        if self.class_id==None:            results1=[]        else:            # 插入sql语句            sql = "SELECT username FROM class WHERE classid='" + self.class_id + "'"            # 执行sql语句            cursor.execute(sql)            # 将数据从数据库读出 类型为多个元组            results = cursor.fetchall()            # 定义一个空列表            results1 = []            # 遍历元组中每个元素,将每个元素转化为字符串并添加至列表中            for item in results:                results1.append(''.join(item))            # 关闭数据库            db.close()        # 返回结果        return results1    #加入班级    def add_class(self):        # ping()使用该方法 ping(reconnect=True)        db.ping(reconnect=True)        #编写sql语句        sql_0 = "INSERT INTO class(username,classid) VALUES(%s,%s)"        sql = sql_0 % (repr(self.username), repr(self.class_id))        cursor.execute(sql)        # 提交到数据库执行        db.commit()        # 关闭数据库        db.close()

app.py代码见下一部分

4.6 展示用户课程及添加课程功能实现

接下来我们对用户课程及添加课程功能进行实现。该功能实现要比上述展示用户班级功能要简单的多。因为课程可以重复添加多次。用户可以学很多的课程,用户也可以不学任何的课程;而对于班级而言,用户仅可以添加一次。所以图中对于展示用户课程以及添加课程功能并没有对此进行判断。由于我们需要在前端页面展示用户的课程号以及课程名,我们将会数据库中返回的元组转成字典,再将字典添加到列表中,最后再模板文件中用Jinja2模板,通过for循环遍历列表,展示到前端页面中。

app.py

# 主界面接口(显示用户登录的用户名即个人信息)@app.route('/index', methods=['GET', 'POST'])  # 这里写入的是接口名称,即URL地址def main_interface():    # 从用户会话中获取到用户名    username = session.get('username')    # 获取用户在前端输入的课程号    course_id = request.form.get('course_id')    # 获取用户在前端输入的课程名    course_name = request.form.get('course_name')    # 创建实例化对象user    user = ud.User(username, '')    # 调用方法,获取用户的班级号    class_id = user.show_user()    # 创建Course_class类中的实例化对象    course_class = ud.Course_class(username, '', class_id)    # 对班级号进行判断,如果班级号为空,并且是POST请求,则将前端数据赋值给该用户    if class_id == None:        if request.method == 'POST':            class_id1 = request.form.get('class-id')            # 赋值完成后,重新创建Course_class类实例化对象            course_class1 = ud.Course_class(username, '', class_id1)            # 调用方法,将班级号加到数据库中            course_class1.add_class()            return redirect('/index')    # 调用展示班级成员的方法    class_member = course_class.show_class_member()    # 创建Course类中的实例化对象    course = ud.Course(username, '', course_id, course_name)    if request.method == 'POST':        course.add_course()    course_list = course.search_course()    # 将用户名 班级号 班级成员 课程列表传入前端    return render_template('index.html', username=username, class_id=class_id, class_member=class_member,                           course_list=course_list)

userdata.py

# 定义课程类 课程类继承于用户类class Course(User):    def __init__(self, username, password, course_id, course_name):        super().__init__(username, password)        self.course_id = course_id        self.course_name = course_name    # 定义查询课程的方法    def search_course(self):        # ping()使用该方法 ping(reconnect=True) ,那么可以在每次连接之前,会检查当前连接是否已关闭,如果连接关闭则会重新进行连接。        db.ping(reconnect=True)        # 插入sql语句        sql = "SELECT courseid,coursename FROM course WHERE username='" + self.username + "'"        # 执行sql语句        cursor.execute(sql)        # 将数据从数据库读出 类型为多个元组        results = cursor.fetchall()        # 定义一个空列表        course_list = []        # 将返回的元组通过遍历转成字典,最后再将字典存入列表中        for items in results:            results1 = [items]            for item in results1:                course_dict = {item[0]: item[1]}                course_list.append(course_dict)        # 关闭数据库        db.close()        return course_list    # 添加课程并加入到数据库    def add_course(self):        # ping()使用该方法 ping(reconnect=True)        db.ping(reconnect=True)        # 插入sql语句        sql_0 = "INSERT INTO course(username,courseid,coursename) VALUES(%s,%s,%s)"        sql = sql_0 % (repr(self.username), repr(self.course_id), repr(self.course_name))        # 执行sql语句        cursor.execute(sql)        # 提交到数据库执行        db.commit()        # 关闭数据库        db.close()

4.7 上传文件及删除文件功能实现

最后我们对上传文件及删除文件功能进行实现,该功能大致流程示意图如图13所示。首先前端页面选择本地磁盘下需要上传的文件,点击上传按钮。在上传接口中我们通过request.file获取到相应的文件,将其存放在static文件夹的uploads文件夹中。接着通过os.walk()函数遍历uploads文件夹下的所有文件,将其存放到列表中,遍历该列表,通过os.path.getctime来获取每个文件的创建时间即上传时间,将其保存至列表中。最后将两个列表通过zip()函数打包至前端页面,前端页面再将其遍历,右上角的数量汇总信息则通过列表的长度来显示。删除文件是在展示上传文件时,每条记录后面添加一个“删除”的a标签,该标签的URL地址为每条记录的文件名。在app接口模块添加相关的视图函数,路由的URL为该文件名。获取需要删除的文件名调用os.remove()函数将其删除,删除完之后再重新,流程如图8所示。至此,本次项目所有功能都已经实现。

图8 上传文件与删除文件

app.py

@app.route('/upload', methods=['POST'])def upload_file():    file_list = []    file_time = []    if request.method == 'POST':        # 获得前端上传的文件        f = request.files['file']        # 将其保存在static下的uploads文件夹中        f.save(path.join(app.config['uploads'], f.filename))        # 对uploads文件夹下所有的文件进行遍历        for item in os.walk(app.config['uploads']):            # os.walk函数执行后,会产生(root,dirs,files)的三元组            # root所指的是当前正在遍历的这个文件夹的本身的地址            # dirs是一个 list,内容是该文件夹中所有的目录的名字(不包括子目录)            # files 同样是 list,内容是该文件夹中所有的文件(不包括子目录)            for items in item[2]:                file_list.append(items)        for items1 in file_list:            # 获取上传文件时的时间,并对其格式化            a = os.path.getctime(app.config['uploads'] + f'/{items1}')            b = time.localtime(a)            c = time.strftime("%Y-%m-%d %H:%M:%S", b)            file_time.append(c)        # 将两个列表打包,方便前端遍历展示        zip_list = zip(file_list, file_time)        return render_template('upload.html', zip_list=zip_list, file_list=file_list)# 删除上传的文件@app.route("/delete/<file>")def delete_file(file):    file_list = []    file_time = []    # 需要删除的文件路径    path = app.config['uploads'] + f"/{file}"    # 删除文件    os.remove(path)    for item in os.walk(app.config['uploads']):        for items in item[2]:            file_list.append(items)    for items1 in file_list:        a = os.path.getctime(app.config['uploads'] + f'/{items1}')        b = time.localtime(a)        c = time.strftime("%Y-%m-%d %H:%M:%S", b)        file_time.append(c)    zip_list = zip(file_list, file_time)    return render_template('upload.html', zip_list=zip_list, file_list=file_list)if __name__ == '__main__':    app.run()

upload.html

<table border=1>                <tr>                    <td colspan=3 style="text-align: center;">资源库</td>                <tr>                    <td>文件名</td>                    <td>上传时间</td>                    <td>操作</td>                </tr>                {% for item,items in zip_list %}                    <tr>                        <td>{{ item }}</td>                        <td>{{ items }}</td>                        <td><a href="/delete/{{ item }}">删除</a></td>                    </tr>                {% endfor %}            </table>

五、设计结果分析

在上面的叙述所我们已经完成了对该项目所有功能的实现,现在让我们运行程序,查看实际的效果。首先我们点击运行,打开网址进入登录界面,为了运行结果的严谨性,我们选择注册账号,输入账号1404和密码123123,点击注册跳转至登录界面,数据库user表中刚刚注册的账号已被加入数据库中,接着输入我们注册的账号和密码并点击登录进入主界面。班级号显示为None,页面显示没有加入相应的班级。我们点击加入班级,输入班级号1002,并点击添加课程输入课程号B01以及课程名Python程序设计,点击提交。相关的信息都已被添加至页面中,接着我们点击侧边栏资源库页面,点击上传文件。上传5个文件并点击删除,将其全部删除,项目运行如图9所示。从图9可以看出此次运行,所有功能都已实现,运行效果很好。

图9 项目运行图

源码地址:https://github.com/JBZ0805/yu_ke_tang.git

PythonWeb 基于Flask框架+MySQL+html实现雨课堂系统相关推荐

  1. 一个基于Flask框架做的仿QQ邮箱系统(收发邮件、贝叶斯模型训练、垃圾邮件过滤、个性化标签)

    一个基于Flask框架做的仿QQ邮箱系统(收发## 标题邮件.贝叶斯模型训练.垃圾邮件过滤.个性化标签) 1.贝叶斯邮件垃圾邮件分类 对上千封邮件进行贝叶斯模型分类训练,对基本邮件实现垃圾分类效果. ...

  2. 基于Python的Flask框架开发的在线电影网站系统(附源码)

    来源丨网络 今天给大家分享的是基于Python的Flask框架开发的在线电影网站系统. 项目介绍 项目介绍:网站前端采用HTML5编写,使用Bootstrap前端开发框架,后端使用Python3语言编 ...

  3. 开发了一款基于 Flask 框架的在线电影网站系统(附 Python 源码)

    文章目录 前言 项目介绍 源码获取 运行环境 安装依赖库 项目截图 首页展示图 视频展示页 视频播放页 后台管理页 整体架构设计图 项目目录结构图 前台功能模块图 后台功能模块图 本地运行图 前言 今 ...

  4. 基于Flask框架的任务管理系统

    基于Flask框架的任务管理系统 基本功能: 任务的添加.删除.查看.编辑.点击完成 用户登录.登出 ##数据库层 任务: 任务id号 任务名 任务添加时间 任务的状态(完成/未完成) 任务所属部门( ...

  5. 展示一下基于flask框架的网页播放器的代码

    <p>下面是基于Flask框架的网页播放器的代码:from flask import Flaskapp = Flask(<strong>name</strong>) ...

  6. 前端—基于Flask框架调用百度接口实现语音识别功能(使用蓝图blueprint)

    配合"基于Flask框架调用百度接口实现语音识别功能"使用的前端参考代码 后端代码链接 Python-基于Flask框架调用百度接口实现语音识别功能:基于Flask框架调用百度接口 ...

  7. 基于SSM框架+MySQL的超市订单管理系统【源码+文档+PPT】

    目录 1.系统需求分析 1.1 系统功能分析 1.2 系统功能需求 1.3 系统性能需求 2.数据库设计 2.1 数据库需求分析 3.数据库物理结构设计 4.各功能模块的设计与实现 4.1 开发框架 ...

  8. 【Python】基于 Flask 框架,模拟微信朋友圈的服务端

    [Python]基于 Flask 框架,模拟微信朋友圈的服务端 一.目的:模拟微信朋友圈的服务端,需要满足以下场景: 1.发表内容时带上图片信息,内容包括(具体内容和id,id指定全局唯一标识),客户 ...

  9. 基于flask框架web代码pyinstaller打包

    场景概述 最近本人在开发基于flask框架的python web,想把代码保密,且不想太多的文件和依赖,因此研究了利用pyinstaller打包成一个可执行文件. 软件环境 Ubuntu:版本14.0 ...

最新文章

  1. 关于从 coding 拉项目的操作
  2. catia曲面扫掠命令详解_Catia曲面基础与工程实践 3.2 扫掠曲面
  3. 能不做自己写个类,也叫java.lang.String
  4. spring aop 中@annotation()和自定义注解的使用
  5. Spring : SpringBoot的ApplicationRunner和CommandLineRunner
  6. Hbase备份与恢复(快照技术)
  7. 备份文件到本地服务器失败,已解决: 备份index/boostrap ,备份filesystem 失败 - Dell Community...
  8. 除了输入法,移动端AI还有哪些想象空间?
  9. 软考中级网络工程师全面学习笔记第2版(5万字)+配套视频及课件
  10. 内网基础-隧道技术、内网穿透(SSH隧道、Socket隧道、跨路由扫描)
  11. linux怎么做冗余备份,linux下使用raid实现冗余备份
  12. 如何使域名跳转到个人博客
  13. Excel如何统计数据个数
  14. 多传感器数据融合发展综述
  15. EasyExcel设置行中单个单元格的样式
  16. 图像修复 2021 最新综述——附综述论文分享
  17. 在中国人群中感染率最高的高危型HPV病毒是HPV16、HPV52和HPV58
  18. CPLEX+Yalmip的MATLAB环境安装
  19. 实现敌人(怪物)的简单AI(自动巡逻、看到玩家攻击玩家、玩家离开恢复自动巡逻)
  20. MSP432E401Y学习笔记day1

热门文章

  1. SwitchHosts!:修改 hosts 文件的方便助手
  2. c语言编译英语翻译器,【图片】【C语言】【windows】---在线翻译器【erbi_lucifer吧】_百度贴吧...
  3. GBASE助力山东移动大数据平台PB级数据主仓业务跨机房无感知迁移
  4. Redis常见面试题你都掌握了没
  5. 修改远程计算机 时间,修改远程计算机系统时间
  6. 凤凰心计鸿蒙石有怎么用,《凤凰心计》试玩:春眠梦缥缈 来化境探幽进行一场奇妙冒险...
  7. 渲染新选择——Corona Renderer 7 惊艳发布
  8. 游戏运维编年史|可能是目前最详细的游戏运维指南(转载附链接)
  9. asp html本地测试工具,ASP本地调试工具
  10. dvwa小马上传大马php,集训第六天:文件上传漏洞