文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

python学生管理系统(pyqt5 含界面)

2023-09-04 14:06

关注

项目模块

账号登陆

人脸识别

增添学生信息

删除学生信息

改动学生信息

查询学生信息

在这里插入图片描述

  1. PyQt5
  2. Mysql
  3. 线程与进程
  4. docker

安装docker

使用daocloud脚本安装docker。

curl -sSL https://get.daocloud.io/docker | sh

检查安装状态

sudo service docker status(q退出)

或者docker -v

安装Mysql

拉取mysql。

docker pull mysql

创建一个目录存放mysql数据文件。

mkdir mysql

进入mysql目录。

cd mysql

启动mysql。(scc110186为密码,自己设置,开放安全组3306端口)

docker run --name mysqlserver -v $PWD/conf:/etc/mysql/conf.d -v $PWD/logs:/logs -v $PWD/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=scc110186 -d -i -p 3306:3306 mysql:latest

查看mysql在容器的名称。

docker ps -a

进入docker mysql容器。

docker exec -it mysqlserver bash

连接mysql。

mysql -uroot -pscc110186

执行命令。

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'scc110186';

打开SQLyog等数据库连接软件,输入主机地址,用户名,密码,进行连接,即可连接成功。

Mysql数据库操作部分

连接数据库

首先,因为我们的代码中,经常出现增删查改的部分,那么我们可以认为这个部分就是高频调用部分,那么一般我们再写项目的时候,我们可以将高频调用的部分,直接放入我们的函数中,再用一个类对这些函数统一进行封装,来封装出类的方法。
那么首先我们的类的初始化部分,一定要对数据库进行连接,然后创建游标。用self来修饰变量,使他们可以在整个类中被访问到。
下面的代码涉及到数据库参数的部分,被我清除了,请大家自行写入。

class db_handle:    def __init__(self):        # 初始化自动连接Mysql数据库        self.db = pymysql.connect(host="",      user="",      password="",      database="")        self.cur = self.db.cursor()

上面的代码中self.db和self.cur为整个db_handle类中公用的部分。所以我们可以在类的方法中进行调用、访问。

账号密码登陆验证

其次就是账号密码登录部分,我们可以封装一个方法,接受两个形参,一个是账号,一个是密码。因为账号为数据库的主键,所以账号是唯一的,所以我们可以通过搜索账号,获取数据库中存储的密码,来进行验证。代码如下:

def login_check(self, id, pwd):    """    登录时账号密码的检查函数    Author:SCC    :param id: 账号    :param pwd: 密码    :return: True / False    """    sql_message = "SELECT pwd FROM login_db WHERE id='{}'".format(id)  # 因为 id 为主键    self.cur.execute(sql_message)    data = self.cur.fetchall()    logger.debug(data)    right_pwd = data[0][0]    if pwd == right_pwd:        return True    else:        return False

那么我们可以看到一个搜索数据库的一个方法。SELECT ? FROM ? WHERE ?。搜索到的结果一般是以元组来装载的,在元组中又是一个又一个小的元组。我们可以通过下标进行访问。用for或while进行遍历输出。函数的返回值为True或者False。这样我们的界面在调用函数时,就可以清楚的知道账号密码是否正确。同时可以通过if判断来对函数返回值的True和False做判断,实现登陆界面是否跳转主界面的逻辑。

搜索表内所有学生数据

在界面打开后我们需要搜索所有学生的信息,并显示在tableWidget控件上。那么我们可以继续使用搜索语句,搜索数据库中所有的学生信息。

def info_init(self):    sql_message = "SELECT * FROM student_info"  # 搜索所有学生信息数据    self.cur.execute(sql_message)  # 执行语句    datas = self.cur.fetchall()  # 获取所有信息结果    logger.debug(datas)    data_list = [data for data in datas]    return data_list

上面就是对所有学生信息进行查询的方法,在查询之后,将每一组学生数据通过列表进行存储。上述存储方式使用的为列表推导式。如果为初学阶段,可以改为如下代码。

for data in datas:    data_list.append(data)

上面为简易版本,但是速度上存在差异,不适用于高数据IO时进行使用。如果可以的话,甚至可以封装一个queue队列,进行先入先出显示。存储在线程中。会让程序更加高效。

删除学生信息

现在就是我们进入增删改查部分的编写了,我们要先对学生的信息删除进行编写。代码如下:

def remove(self, name, id, class_text, phone, addr):    sql_message = "DELETE FROM student_info WHERE name='{}'" \                  " and id='{}'" \                  " and class='{}'" \                  " and phone='{}'" \                  " and addr='{}'".format(name, id, class_text, phone, addr)    self.cur.execute(sql_message)    self.db.commit()

上述代码中包含了删除的书写方式,同时可以将删除部分写在一行中,但是因为Python书写规范中明确表明:一行字符最多不能超过120个,所以使用这种方式更加规范,易读。

增加、更改、查询学生信息

剩下的代码就是增删改查中增、改、查部分了。主题思路与删除一致。不过多赘述。

def search(self, name):    sql_message = "SELECT * FROM student_info WHERE name='{}'".format(name)    self.cur.execute(sql_message)    datas = self.cur.fetchall()    data_list = [data for data in datas]    return data_listdef insert(self, name, id, class_text, phone, addr):    sql_message = "INSERT INTO student_info(name, id, class, phone, addr)" \                  " values('{}', '{}', '{}', '{}', '{}')".format(name, id, class_text, phone, addr)    self.cur.execute(sql_message)    self.db.commit()def change(self, name, id, class_text, phone, addr, oname, oid, oclass_text, ophone, oaddr):    sql_message = "UPDATE student_info set name='{}',id='{}',class='{}',phone = '{}',addr='{}'" \                  "where name = '{}' and id='{}' and class='{}' and phone = '{}' and addr='{}'".format(        name, id, class_text, phone, addr, oname, oid, oclass_text, ophone, oaddr    )    self.cur.execute(sql_message)    self.db.commit()

UI界面设计

因为初版为Demo版本所以界面,没有过多美化。大家可以自行添加QSS进行修改。先给大家放一下我们两个界面的设计图。
在这里插入图片描述

上面这个就是用控件图绘制的界面。

登陆界面

下面我们来讲一下登陆界面的逻辑,首先登录界面有账号密码登录,人脸识别登录。因为人脸识别涉及到了一些dll动态链接库和一些不同操作系统下的检测,并且算法属于实验室二次开发出来的,就不在这里进行展示。只展示账号密码部分的逻辑。
账号密码的逻辑就是将我们两个输入框的文本进行获取,在获取之后,进行一个数据库的比对,正确时进行界面跳转,错误是弹窗警报。

退出与最小化

我们的界面需要退出或者最小化,而这个又是最好实现的功能。那么我们就看一下这个应该如何去写。

self.close_btn.clicked.connect(lambda: sys.exit())self.mini_btn.clicked.connect(lambda: self.showMinimized())

我们直接定义两个按钮的信号与槽,然后绑定一个匿名函数,一个用于关闭系统,另一个用于最小化界面。匿名函数看不懂的话,可以写成如下效果。

self.close_btn.clicked.connect(self.close_ui)self.mini_btn.clicked.connect(self.minisize_ui)def close_ui(self):    self.close()    def minisize_ui(self):    self.showMinimized()

数据库匹配登录

我们可以像如下代码一样编写一个登录验证的函数,并且绑定信号与槽,这里我就不写绑定部分了,可以从上一部分学习一下。

    def login(self):        """        进行登陆的函数        Author:SCC        :return: None        """        try:            id_text = self.id_edit.text()            pwd_text = self.pwd_edit.text()        except BaseException as e:            QMessageBox.about(self, 'Error', '请正确输入账号或密码!')            return        if id_text.replace(" ", "") == "" or pwd_text.replace(" ", "") == "":            QMessageBox.about(self, 'Error', '请正确输入账号或密码!')        else:            logger.debug(id_text)            logger.debug(pwd_text)            if self.db_handle.login_check(id_text, pwd_text):                logger.debug("ok")                self.cap.release()                self.info_ui = info_ui()                self.info_ui.show()                self.close()            else:                QMessageBox.about(self, 'Error', '账号或密码错误!')

在这里我们为了防止出现Bug,接入了一个try except。因为无论何时,我们都不能保证用户是一个正常的思维使用我们的项目,他可能不输入,也可能乱输入。所以要进行报错处理。在获取输入之后,我们将数据放入Mysql中进行匹配查找。当查找函数返回为True,代表查找结果成功,存在对应的数据。相对应的登陆成功,出现登录成功的弹窗。但是若返回参数为False,那么代表数据库中未找到匹配的人员信息,那么登录失败,出现帐号或密码错误的弹窗。

界面跳转

界面跳转讲几个步骤。

  1. 首先实例化第一个类
  2. 其次显示这个界面
  3. 最后关闭当前界面
self.info_ui = info_ui()  # 实例化新的界面类self.info_ui.show()  # 显示新界面self.close()  # 关闭当前界面

信息管理界面

数据准备

我们在界面跳转后,进入我们的增删改查界面,首先我们要将学生的信息自动显示在tableWidget中,那么对于大量的数据IO,我们不能将查找的算法直接写在进程中,因为这样在大量数据出现时,容易导致进程阻塞,最后界面进入假死状态。所以我们要写到对应的线程中。
线程是一个在后期经常使用的写法,因为一个程序中多个功能同步或异步进行的情况非常多,如果将所有代码放在一个进程中,一定会出现一些卡顿,甚至是异常状态。那么这个时候我们一般将线程放置到我们的代码中,来解决这样的问题。代码如下:

class db_init(QThread):    def __init__(self, info_ui):        super(db_init, self).__init__()        self.info_ui = info_ui        self.data_list = None        self.db_handle = db_handle()    def run(self):        self.info_ui.tableWidget.clearContents()        self.data_list = self.db_handle.info_init()        logger.debug(self.data_list)        self.info_ui.tableWidget.setRowCount(len(self.data_list))        for i in range(len(self.data_list)):            for y in range(5):                nameitem = QTableWidgetItem(QtWidgets.QTableWidgetItem(self.data_list[i][y]))                nameitem.setTextAlignment(Qt.AlignCenter)  # 中对齐                self.info_ui.tableWidget.setItem(i, y, nameitem)

我们的线程会将数据放入到tablewidget中,进行显示。
那么我们来看一下代码,首先我们声明一个类,名为db_init,他绑定了一个QThread,并继承于info_ui界面。那么这个线程在初始化时,只是将我们提前准备的数据库操作的类进行了初始化。而他的run方法中,是一个完整的搜索数据库并显示在界面中的算法。这样我们的线程就创建好了。我们只需要在需要他的时候,进行实例化,并且将它开启。当线程执行结束后,将自动停止,但是也可以手动调用stop方法,停止线程。

主界面逻辑

接下来,我们要写的是主界面的一些逻辑,我们要绑定所有按钮的信号与槽,让他们在被点击后可以有自己的处理事件。首先是增加学生。也就是数据库的增添函数。

def add_stu(self):    add_name = self.info_name.text()    add_id = self.info_id.text()    add_class = self.info_class.text()    add_phone = self.info_phone.text()    add_addr = self.info_addr.text()    try:        if add_name == "" or add_id == "" or add_class == "" or add_phone == "" or add_addr == "":            QMessageBox.about(self, 'Error', '请将数据输入完整!')        else:            self.db_handle.insert(add_name, add_id, add_class, add_phone, add_addr)            self.tableWidget.clearContents()            self.data_list = self.db_handle.info_init()            self.tableWidget.setRowCount(len(self.data_list))            for i in range(len(self.data_list)):                for y in range(5):                    nameitem = QTableWidgetItem(QtWidgets.QTableWidgetItem(self.data_list[i][y]))                    nameitem.setTextAlignment(Qt.AlignCenter)  # 中对齐                    self.tableWidget.setItem(i, y, nameitem)    except:        QMessageBox.about(self, 'Error', '数据重复!')

我们要获取学生的姓名班级学号这些输入框,同时大家可以加上一些判断,例如是否输入的是数字,学号是否符合规则等。这样会让程序更加的稳定。我们将几个数据传入数据库中,进行添加,然后加一个刷新数据库和界面的功能,让我们的程序显得更加智能化。
这里我们依然是调用的我们写好的数据库操作类进行的添加。所以我们可以看出,这些函数是非常常用的函数,所以在封装之后,我们可以很轻松的调用他们。
当数据出现重复时,我们可以直接进行弹窗提醒。那么如何监测的重复,我们可以理解为学生的姓名也许可以重复,学生的地址可以重复,但是学号和电话号不会重复,那么在Mysql中我们可以将这两列作为我们区分的条件。
其次就是删除学生,首先我们要获取我们的tablewidget点击事件。在触发点击事件后我们可以获取点击事件的行和列。那么根据行和列的参数,就可以获取到我们想删除的学生信息。

def salegoodsselect(self, row):    self.name = self.tableWidget.item(row, 0).text()    self.id = self.tableWidget.item(row, 1).text()    self.class_text = self.tableWidget.item(row, 2).text()    self.phone = self.tableWidget.item(row, 3).text()    self.addr = self.tableWidget.item(row, 4).text()

在获取到数据后,我们将当前学生的各个信息存储至变量中,随后我们就可以执行删除函数。同时我们将参数进行传入,让数据库操作删除指定的一行数据。
但是,同时我们要注意一些小的细节。如果我不进行点击,我就单独进行删除,那么现在我们的存储信息的变量的值就是None。那么如果将None传入Mysql,肯定会导致报错。所以在执行前我们要进行一个判断,在发现结果为None是,我们就显示一个请选择删除人员的弹窗。

def remove_stu(self):    if self.name is None or self.id is None or self.class_text is None or self.phone is None or self.addr is None:        QMessageBox.about(self, 'Error', '请先选择删除人员!')        return    else:        self.db_handle.remove(self.name, self.id, self.class_text, self.phone, self.addr)        self.tableWidget.clearContents()        self.data_list = self.db_handle.info_init()        self.tableWidget.setRowCount(len(self.data_list))        for i in range(len(self.data_list)):            for y in range(5):                nameitem = QTableWidgetItem(QtWidgets.QTableWidgetItem(self.data_list[i][y]))                nameitem.setTextAlignment(Qt.AlignCenter)  # 中对齐                self.tableWidget.setItem(i, y, nameitem)

删除后,同样自动进行更新函数。
然后是改动的函数,这个函数同样需要依赖获取我们点击tablewidget的事件,同时获取我们的输入框信息,将信息存储至变量中,进行判断,确保已经获取到点击人员的信息。同时我们判断一下输入框中是否有数据。同时可以加上一些输入信息是否合理的判断。在判断全都通过后,进行数据的上传,同时要确定数据没有重复的情况。

def change_stu(self):    add_name = self.info_name.text()    add_id = self.info_id.text()    add_class = self.info_class.text()    add_phone = self.info_phone.text()    add_addr = self.info_addr.text()    if self.name is None or self.id is None or self.class_text is None or self.phone is None or self.addr is None:        QMessageBox.about(self, 'Error', '请先选择修改人员!')        return    try:        if add_name == "" or add_id == "" or add_class == "" or add_phone == "" or add_addr == "":            QMessageBox.about(self, 'Error', '请将数据输入完整!')        else:            self.db_handle.change(add_name, add_id, add_class, add_phone, add_addr, self.name, self.id, self.class_text, self.phone, self.addr)            self.tableWidget.clearContents()            self.data_list = self.db_handle.info_init()            self.tableWidget.setRowCount(len(self.data_list))            for i in range(len(self.data_list)):                for y in range(5):                    nameitem = QTableWidgetItem(QtWidgets.QTableWidgetItem(self.data_list[i][y]))                    nameitem.setTextAlignment(Qt.AlignCenter)  # 中对齐                    self.tableWidget.setItem(i, y, nameitem)    except BaseException as e:        logger.debug(e)        QMessageBox.about(self, 'Error', '数据重复!')

最后是查询函数,我们需要先获取输入框中的文本,确定我们要找到的学生姓名,然后传输到数据库中进行查找,获取他在数据库中的数据,最后将数据进行整合,显示在tablewidget中。

def search_stu(self):    if self.name_edit.text() != "":        data_list = self.db_handle.search(self.name_edit.text())        self.tableWidget.clearContents()        self.tableWidget.setRowCount(len(data_list))        for i in range(len(data_list)):            for y in range(5):                nameitem = QTableWidgetItem(QtWidgets.QTableWidgetItem(data_list[i][y]))                nameitem.setTextAlignment(Qt.AlignCenter)  # 中对齐                self.tableWidget.setItem(i, y, nameitem)    else:        self.tableWidget.clearContents()        self.data_list = self.db_handle.info_init()        self.tableWidget.setRowCount(len(self.data_list))        for i in range(len(self.data_list)):            for y in range(5):                nameitem = QTableWidgetItem(QtWidgets.QTableWidgetItem(self.data_list[i][y]))                nameitem.setTextAlignment(Qt.AlignCenter)  # 中对齐                self.tableWidget.setItem(i, y, nameitem)

来源地址:https://blog.csdn.net/weixin_50153843/article/details/128528261

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯