学生信息管理系统

本案例由3个页面组成:

  1. 登录页面
  2. 注册页面
  3. 数据操作页面

用户若想使用我们这个系统,必须先注册,注册成功之后自动打开登录页面,登录成功即进入数据操作页面

案例展示

数据库创建

当前我们是要来开发一个新的项目,为了不和其它数据库糅杂在一下,我们就来新建一个数据库吧!

1
create database itheima;

创建完数据库还不行啊,我们最好还能让管理员给我们一个账号,该账号只能在itheima这个数据库中使用,所以我们需要使用root账号登陆

例如,我们创建一个系统管理员账号:admin 密码:123456

1
create user admin@'localhost' identified by '123456'

创建完用户,我们还不要忘记对该用户授予itheima这个数据库下所有的权限喔!

1
grant all privileges on itheima.* to admin@'localhost';

至此,我们为这个新项目所做的数据库准备工作就完成啦!

表的创建

我们去创建一张专门用于存放系统使用人员的表,让它和我们系统要记录的学生信息表分开

例如,我们创建一张users的表专门用于存放管理员门的表

1
2
3
4
5
6
create table if not exists user(
    id int primary key auto_increment,
    username varchar(20),
    password varchar(50),
    nickname varchar(20)
);

创建一张专门用于保存学生信息的表student

1
2
3
4
5
6
create table if not exists student(
                    sid int primary key auto_increment,
                    name varchar(20),
                    age int,
                    gender varchar(2)    
              )

搭建主窗体

主窗体拥有一个菜单栏,它里面有个操作选项,我们可以进行菜单切换,所以这里我们需要操作菜单栏

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 添加操作菜单
menu_bar = self.window.menuBar()
operate_menu =menu_bar.addMenu("操作")

# 向菜单中添加两个动作
loginAction = QAction("登录")
loginAction.triggered.connect(self.show_login)
operate_menu.addAction(loginAction)

registerAction = QAction("注册")
registerAction.triggered.connect(self.show_register)
operate_menu.addAction(registerAction)

要想实现窗体的切换,我们还需要使用QT中的自定义信号

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from PyQt5.QtCore import pyqtSignal


class LoginWidget(QWidget):
    # 声明一个信号
    login_success = pyqtSignal()

    ....

    # 向外发送一个信号
    self.login_success.emit()

完整的主窗体实现代码如下

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
from pymysql import connect
from PyQt5.QtWidgets import QApplication,QMainWindow,QAction
from RegisterWidget import RegisterWidget
from LoginWidget import LoginWidget
from IndexWidget import IndexWidget
import sys

class StuSystem:

    def __init__(self):
        # 初始化数据库
        # self.create_db()

        # 创建一个应用程序
        app = QApplication(sys.argv)

        # 创建一个主窗体
        self.mainWindow = QMainWindow()
        # 设置窗口的固定大小
        self.mainWindow.setFixedSize(800,400)

        # 给窗口增加一个菜单栏
        menuBar = self.mainWindow.menuBar()
        operation = menuBar.addMenu("操作")

        # 给菜单添加动作
        loginAction = QAction("登录")
        # 将loginAction添加到操作这个菜单里
        operation.addAction(loginAction)
        # 设置loginAction的信号和槽
        loginAction.triggered.connect(self.show_login)

        # 给菜单添加注册的动作
        registerAction = QAction("注册")
        # 将registerAction添加到这个菜单中
        operation.addAction(registerAction)
        # 设置RegisterAction的信号和槽
        registerAction.triggered.connect(self.show_register)

        # 默认打开注册页面
        self.show_index()

        # 将主窗口显示出来
        self.mainWindow.show()
        # 让程序一直处于运行的状态
        sys.exit(app.exec())

    def show_index(self):
        print("显示主要功能页")
        indexWidget = IndexWidget()
        self.mainWindow.setCentralWidget(indexWidget)

    def show_login(self):
        print("显示登录页面")
        loginWidget = LoginWidget()
        loginWidget.login_success.connect(self.show_index)
        self.mainWindow.setCentralWidget(loginWidget)

    def show_register(self):
        print("显示注册页面")
        registerWidget = RegisterWidget()
        # 绑定信号和槽
        registerWidget.register_success.connect(self.show_login)
        self.mainWindow.setCentralWidget(registerWidget)



    def create_db(self):
        # 建立连接
        conn = connect(host="localhost",port=3306,user="admin",password="123456")

        # 获取执行SQL的游标
        cursor = conn.cursor()

        # 创建数据库
        sql = "create database if not exists itheima"
        # 执行sql
        cursor.execute(sql)
        # 选中数据库
        cursor.execute("use itheima")
        # 创建管理员账号表
        sql = """create table if not exists user(
    id int primary key auto_increment,
    username varchar(20),
    password varchar(50),
    nickname varchar(20)
);"""
        # 创建表
        cursor.execute(sql)

        # 创建用于保存学生数据的表
        sql = """create table if not exists student(
                    sid int primary key auto_increment,
                    name varchar(20),
                    age int,
                    gender varchar(2)    
              )"""
        cursor.execute(sql)

        # 释放资源
        cursor.close()
        # 断开连接
        conn.close()


if __name__ == '__main__':
    StuSystem()

编写注册页面

代码实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
from PyQt5.QtWidgets import *
from PyQt5.Qt import QFont
from PyQt5.QtCore import pyqtSignal

class RegisterWidget(QWidget):
    # 定义一个注册成功的信号
    register_success = pyqtSignal()

    def __init__(self):
        super(RegisterWidget, self).__init__()

        # 整个注册页面是水平布局
        hbox = QHBoxLayout(self)

        hbox.addStretch()

        # 添加要显示的内容
        vbox = QVBoxLayout()
        label = QLabel("学生管理系统")
        font = QFont("微软雅黑",30)
        font.setBold(True)
        label.setFont(font)
        vbox.addWidget(label)
        hbox.addLayout(vbox)

        # 添加注册信息框
        formLayout = QFormLayout()

        self.usernameEdit = QLineEdit()
        formLayout.addRow("用户名:",self.usernameEdit)

        self.passwordEdit = QLineEdit()
        self.passwordEdit.setEchoMode(QLineEdit.Password)
        formLayout.addRow("密码:", self.passwordEdit)

        self.nicknameEdit = QLineEdit()
        formLayout.addRow("昵称:", self.nicknameEdit)

        pushButton = QPushButton("注册")
        pushButton.clicked.connect(self.register)
        formLayout.addRow("",pushButton)


        vbox.addLayout(formLayout)

        hbox.addStretch()

    def register(self):
        # print("假装注册逻辑已经完成啦!")
        # 获取用户输入的内容
        username = self.usernameEdit.text()
        password = self.passwordEdit.text()
        nickname = self.nicknameEdit.text()

        from pymysql import connect
        conn = connect(host="localhost",port=3306,user="admin",password="123456",database="itheima")

        sql = "insert into user values(null,%s,%s,%s)"

        cursor = conn.cursor()
        ret = cursor.execute(sql,[username,password,nickname])
        # 需要提交事务
        conn.commit()

        if ret==1:
            print("注册成功!")
            QMessageBox.information(None, '提示', '恭喜您,注册成功!')
            # 发送信号
            self.register_success.emit();

        # 释放资源
        cursor.close()
        # 断开连接
        conn.close()

编写登录页面

代码实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
from PyQt5.QtWidgets import *
from PyQt5.Qt import QFont
from PyQt5.QtCore import pyqtSignal

class LoginWidget(QWidget):
    # 定义一个注册成功的信号
    login_success = pyqtSignal()

    def __init__(self):
        super(LoginWidget, self).__init__()

        # 整个注册页面是水平布局
        hbox = QHBoxLayout(self)

        hbox.addStretch()

        # 添加要显示的内容
        vbox = QVBoxLayout()
        label = QLabel("学生管理系统")
        font = QFont("微软雅黑",30)
        font.setBold(True)
        label.setFont(font)
        vbox.addWidget(label)
        hbox.addLayout(vbox)

        # 添加注册信息框
        formLayout = QFormLayout()

        self.usernameEdit = QLineEdit()
        formLayout.addRow("用户名:",self.usernameEdit)

        self.passwordEdit = QLineEdit()
        self.passwordEdit.setEchoMode(QLineEdit.Password)
        formLayout.addRow("密码:", self.passwordEdit)

        pushButton = QPushButton("登录")
        pushButton.clicked.connect(self.login)
        formLayout.addRow("",pushButton)


        vbox.addLayout(formLayout)

        hbox.addStretch()

    def login(self):
        # 获取用户输入的内容
        username = self.usernameEdit.text()
        password = self.passwordEdit.text()

        from pymysql import connect
        conn = connect(host="localhost", port=3306, user="admin", password="123456", database="itheima")

        sql = "select * from user where username=%s and password=%s"

        cursor = conn.cursor()
        cursor.execute(sql, [username, password])

        user = cursor.fetchone();

        if user:
            print("登录成功!")
            # 发送信号
            self.login_success.emit();
        else:
            QMessageBox.information(None,"提示","用户名或密码错误!")

        # 释放资源
        cursor.close()
        # 断开连接
        conn.close()

补充:在这个案例中,我们的所有密码都是明文存储的,为了安全起见,我们其实可以将我们的密码加密之后再保存到数据库中

这里我们可以使用md5这种加密方式,例如

1
2
str = "123456"
m = hashlib.md5(str.encode("utf-8")).hexdigest()

如果你觉得采用这种方式还是不安全的话,我们还可以对我们的md5加密算法进行加盐操作,让用户输入的值拼接上一个特殊的字符串

1
2
str = "123456"+"&%%*(%)"
m = hashlib.md5(str.encode("utf-8")).hexdigest()

编写项目主页

在这一小节中,我们将给大家介绍qt中是如何去操作数据库的!

首先我们要给大家介绍的是QT中如何进行数据库的连接

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    # 创建一个QT数据库客户端,这里的参数不能瞎填, https://doc.qt.io/qt-5/qsqldatabase.html#addDatabase
    db =  QSqlDatabase.addDatabase("QMYSQL")
    # 设置host
    db.setHostName("localhost")
    # 设置端口号
    db.setPort(3306)
    # 设置连接用户名
    db.setUserName("admin")
    # 设置连接的密码
    db.setPassword("123456")
    # 设置连接的数据库名称
    db.setDatabaseName("itheima")

    # 打开数据库
    db.open()

如果想使用QT直接执行SQL命令的话,我们需要用到QSQLQuery

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 传入上面创建好的数据库客户端即可
query = QSqlQuery(db)

# 执行建表语句
query.exec("""
                  create table if not exists student(
                        sid int primary key,
                        name varchar(20),
                        age int,
                        sex varchar(2)
                    );
               """)


def test_query(db):
    query = QSqlQuery(db)
    ret = query.exec("select * from student")
    print(ret)
    while query.next():
        print(query.value(0))
        print(query.value(1))
        print(query.value(2))
        print(query.value(3))
        print("====================")


def test_insert(db):
    query = QSqlQuery(db);
    ret = query.exec("insert into student values(%d,'%s',%d,'%s')"%(2001,"老王",36,"男"))
    print(query.lastError().text())
    print(ret)

def test_update(db):
    query = QSqlQuery(db);
    ret = query.exec("update student set name='%s' where name='%s'"%("小王","老王"))
    print(query.lastError().text())
    print(ret)

def test_delete(db):
    query = QSqlQuery(db);
    ret = query.exec("delete from student where sid=%d"%2001)
    print(query.lastError().text())
    print(ret)

注意:

qt库中默认缺少mysql的驱动,

若python是32位的,则需要提供32位的libmysql.dll文件

若python是64位的,则需要提供64位的libmysql.dll文件

并将它复制到python安装目录\Lib\site-packages\PyQt5\Qt\bin

代码实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
from PyQt5.QtWidgets import *
from PyQt5.QtSql import QSqlTableModel,QSqlDatabase
from PyQt5.QtCore import Qt


class IndexWidget(QWidget):

    def __init__(self):
        super(IndexWidget, self).__init__()

        hbox = QHBoxLayout(self)

        # 左侧按钮组
        groupBox = QGroupBox("数据库操作")
        hbox.addWidget(groupBox)
        # 设置groupBox布局方式
        vbox = QVBoxLayout()
        groupBox.setLayout(vbox)

        # 查看
        query_btn = QPushButton("查看数据")
        query_btn.clicked.connect(self.query_db)
        vbox.addWidget(query_btn)
        # 增加
        add_btn = QPushButton("增加一行")
        add_btn.clicked.connect(self.add)
        vbox.addWidget(add_btn)
        # 删除
        delete_btn = QPushButton("删除一行")
        delete_btn.clicked.connect(self.delete)
        vbox.addWidget(delete_btn)
        # 退出
        exit_btn = QPushButton("退出")
        exit_btn.clicked.connect(QApplication.exit)
        vbox.addWidget(exit_btn)

        # 右侧表格显示区域
        self.tableView = QTableView()
        hbox.addWidget(self.tableView)

        # 创建一个QT数据库客户端
        db =  QSqlDatabase.addDatabase("QMYSQL")
        # 设置host
        db.setHostName("localhost")
        # 设置端口号
        db.setPort(3306)
        # 设置连接用户名
        db.setUserName("admin")
        # 设置连接的密码
        db.setPassword("123456")
        # 设置连接的数据库名称
        db.setDatabaseName("itheima")

        # 打开数据库
        db.open()

        self.tableModel = QSqlTableModel(db=db)
        self.tableModel.setTable("student")
        self.tableModel.setEditStrategy(QSqlTableModel.OnFieldChange)

        self.tableModel.setHeaderData(0,Qt.Horizontal,"学号")
        self.tableModel.setHeaderData(1,Qt.Horizontal,"姓名")
        self.tableModel.setHeaderData(2,Qt.Horizontal,"年龄")
        self.tableModel.setHeaderData(3,Qt.Horizontal,"性别")

        # 将封装好的模型交给tableWidget
        self.tableView.setModel(self.tableModel)

    def query_db(self):
        print(self.tableModel.lastError().text())
        self.tableModel.select()

    def add(self):
        self.tableModel.insertRow(self.tableModel.rowCount())

    def delete(self):
        # 找到当前选中行的下标
        index = self.tableView.currentIndex().row()
        self.tableModel.removeRow(index)
        self.tableModel.select()