Bài 49: Tương tác Python với Cơ sở dữ liệu MySQL Server -Quản lý Sinh viên

Trong bài 48 các bạn đã biết cách sử dụng ngôn ngữ lập trình Python để tương tác cơ sở dữ liệu MySQL Server “studentmanagement”, Các bạn đã lập trình nhuần nhuyễn CRUD để thêm mới dữ liệu, truy vấn dữ liệu, sắp xếp dữ liệu, cập nhật dữ liệu, xóa dữ liệu, phân trang dữ liệu….

Bài học này chúng ta sẽ ứng dụng để thiết kế giao diện tương tác người dùng, giao diện như dưới đây:

Phần mềm sử dụng cơ sở dữ liệu và các mã lệnh đã học ở các bài trước.

Phần mềm gồm có các chức năng sau:

(1) Tải toàn bộ dữ liệu từ bảng student lên QTableWidget

(2) “New”: Xóa dữ liệu trong các Widget để cho nhập mới dữ liệu

(3) “Insert”: Thêm mới student vào cơ sở dữ liệu MySQL

(4) “Update”: Chỉnh sữa dữ liệu student

(5) “Remove”: Xóa Student khỏi cơ sở dữ liệu MySQL

(6) “Avatar”/”Remove Avatar”: Chọn và xóa Avatar. Hình Ảnh sẽ được mã hóa thành base64string

(7) Xem chi tiết student: Nhấn chọn student trong QTableWidget, thông tin chi tiết của Student sẽ hiển thị vào các Widget cơ bản

Ta đi vào chi tiết:

Bước 1: Tạo cấu trúc thư mục và tập tin cho dự án “StudentManagement” như dưới đây:

  • images: Thư mục này lưu các hình ảnh, icon của phần mềm, tùy bạn lựa chọn
  • MainWindow.ui: Tập tin giao diện phần mềm
  • MainWindow.py: Tập tin python gencode của giao diện
  • MainWindowEx.py: Tập tin kết thừa lớp giao diện được tạo ra từ MainWindow.py
  • MyApp.py: Tập tin thực thi phần mềm

Bước 2: Bạn thiết kế giao diện như hình dưới đây:

Thiết kế giao diện, đặt tên các Widget như hình trên.

Bước 3: Sau đó Gencode “MainWindow.py”:

# Form implementation generated from reading ui file 'E:\Elearning\StudentManagement\MainWindow.ui'
#
# Created by: PyQt6 UI code generator 6.7.1
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt6 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(456, 552)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("E:\\Elearning\\StudentManagement\\images/ic_logo.jpg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        MainWindow.setWindowIcon(icon)
        self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.label = QtWidgets.QLabel(parent=self.centralwidget)
        self.label.setGeometry(QtCore.QRect(20, 0, 371, 41))
        font = QtGui.QFont()
        font.setPointSize(12)
        font.setBold(True)
        font.setWeight(75)
        self.label.setFont(font)
        self.label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
        self.label.setObjectName("label")
        self.groupBox = QtWidgets.QGroupBox(parent=self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(20, 450, 411, 61))
        self.groupBox.setStyleSheet("background-color: rgb(236, 255, 199);")
        self.groupBox.setObjectName("groupBox")
        self.pushButtonRemove = QtWidgets.QPushButton(parent=self.groupBox)
        self.pushButtonRemove.setGeometry(QtCore.QRect(300, 20, 91, 28))
        self.pushButtonRemove.setStyleSheet("background-color: rgb(255, 170, 255);")
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap("E:\\Elearning\\StudentManagement\\images/ic_delete.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        self.pushButtonRemove.setIcon(icon1)
        self.pushButtonRemove.setIconSize(QtCore.QSize(24, 24))
        self.pushButtonRemove.setObjectName("pushButtonRemove")
        self.pushButtonInsert = QtWidgets.QPushButton(parent=self.groupBox)
        self.pushButtonInsert.setGeometry(QtCore.QRect(100, 20, 81, 28))
        self.pushButtonInsert.setStyleSheet("background-color: rgb(255, 170, 255);")
        icon2 = QtGui.QIcon()
        icon2.addPixmap(QtGui.QPixmap("E:\\Elearning\\StudentManagement\\images/ic_save.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        self.pushButtonInsert.setIcon(icon2)
        self.pushButtonInsert.setIconSize(QtCore.QSize(24, 24))
        self.pushButtonInsert.setObjectName("pushButtonInsert")
        self.pushButtonNew = QtWidgets.QPushButton(parent=self.groupBox)
        self.pushButtonNew.setGeometry(QtCore.QRect(10, 20, 71, 28))
        self.pushButtonNew.setStyleSheet("background-color: rgb(255, 170, 255);")
        icon3 = QtGui.QIcon()
        icon3.addPixmap(QtGui.QPixmap("E:\\Elearning\\StudentManagement\\images/ic_new.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        self.pushButtonNew.setIcon(icon3)
        self.pushButtonNew.setIconSize(QtCore.QSize(24, 24))
        self.pushButtonNew.setObjectName("pushButtonNew")
        self.pushButtonUpdate = QtWidgets.QPushButton(parent=self.groupBox)
        self.pushButtonUpdate.setGeometry(QtCore.QRect(200, 20, 81, 28))
        self.pushButtonUpdate.setStyleSheet("background-color: rgb(255, 170, 255);")
        icon4 = QtGui.QIcon()
        icon4.addPixmap(QtGui.QPixmap("E:\\Elearning\\StudentManagement\\images/ic_update.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        self.pushButtonUpdate.setIcon(icon4)
        self.pushButtonUpdate.setIconSize(QtCore.QSize(24, 24))
        self.pushButtonUpdate.setObjectName("pushButtonUpdate")
        self.groupBox_2 = QtWidgets.QGroupBox(parent=self.centralwidget)
        self.groupBox_2.setGeometry(QtCore.QRect(20, 240, 411, 201))
        self.groupBox_2.setStyleSheet("background-color: rgb(255, 201, 243);")
        self.groupBox_2.setObjectName("groupBox_2")
        self.label_4 = QtWidgets.QLabel(parent=self.groupBox_2)
        self.label_4.setGeometry(QtCore.QRect(20, 110, 41, 16))
        self.label_4.setObjectName("label_4")
        self.label_3 = QtWidgets.QLabel(parent=self.groupBox_2)
        self.label_3.setGeometry(QtCore.QRect(20, 80, 41, 16))
        self.label_3.setObjectName("label_3")
        self.lineEditName = QtWidgets.QLineEdit(parent=self.groupBox_2)
        self.lineEditName.setGeometry(QtCore.QRect(70, 80, 171, 22))
        self.lineEditName.setStyleSheet("background-color: rgb(251, 255, 206);")
        self.lineEditName.setObjectName("lineEditName")
        self.lineEditAge = QtWidgets.QLineEdit(parent=self.groupBox_2)
        self.lineEditAge.setGeometry(QtCore.QRect(70, 110, 171, 22))
        self.lineEditAge.setStyleSheet("background-color: rgb(251, 255, 206);")
        self.lineEditAge.setObjectName("lineEditAge")
        self.label_2 = QtWidgets.QLabel(parent=self.groupBox_2)
        self.label_2.setGeometry(QtCore.QRect(20, 50, 41, 16))
        self.label_2.setObjectName("label_2")
        self.lineEditCode = QtWidgets.QLineEdit(parent=self.groupBox_2)
        self.lineEditCode.setGeometry(QtCore.QRect(70, 50, 171, 22))
        self.lineEditCode.setStyleSheet("background-color: rgb(251, 255, 206);")
        self.lineEditCode.setObjectName("lineEditCode")
        self.label_5 = QtWidgets.QLabel(parent=self.groupBox_2)
        self.label_5.setGeometry(QtCore.QRect(20, 150, 41, 16))
        self.label_5.setObjectName("label_5")
        self.lineEditIntro = QtWidgets.QLineEdit(parent=self.groupBox_2)
        self.lineEditIntro.setGeometry(QtCore.QRect(70, 140, 171, 41))
        self.lineEditIntro.setStyleSheet("background-color: rgb(251, 255, 206);")
        self.lineEditIntro.setObjectName("lineEditIntro")
        self.labelAvatar = QtWidgets.QLabel(parent=self.groupBox_2)
        self.labelAvatar.setGeometry(QtCore.QRect(250, 10, 151, 141))
        self.labelAvatar.setStyleSheet("background-color: rgb(170, 255, 255);\n"
"border-color: rgb(85, 85, 0);")
        self.labelAvatar.setText("")
        self.labelAvatar.setPixmap(QtGui.QPixmap("E:\\Elearning\\StudentManagement\\images/ic_no_avatar.png"))
        self.labelAvatar.setScaledContents(True)
        self.labelAvatar.setObjectName("labelAvatar")
        self.pushButtonAvatar = QtWidgets.QPushButton(parent=self.groupBox_2)
        self.pushButtonAvatar.setGeometry(QtCore.QRect(250, 160, 61, 23))
        self.pushButtonAvatar.setStyleSheet("background-color: rgb(170, 255, 127);")
        self.pushButtonAvatar.setObjectName("pushButtonAvatar")
        self.label_6 = QtWidgets.QLabel(parent=self.groupBox_2)
        self.label_6.setGeometry(QtCore.QRect(20, 20, 41, 16))
        self.label_6.setObjectName("label_6")
        self.lineEditId = QtWidgets.QLineEdit(parent=self.groupBox_2)
        self.lineEditId.setEnabled(False)
        self.lineEditId.setGeometry(QtCore.QRect(70, 20, 81, 22))
        self.lineEditId.setStyleSheet("background-color: rgb(251, 255, 206);")
        self.lineEditId.setReadOnly(True)
        self.lineEditId.setObjectName("lineEditId")
        self.pushButtonRemoveAvatar = QtWidgets.QPushButton(parent=self.groupBox_2)
        self.pushButtonRemoveAvatar.setGeometry(QtCore.QRect(320, 160, 81, 23))
        self.pushButtonRemoveAvatar.setStyleSheet("background-color: rgb(170, 255, 127);")
        self.pushButtonRemoveAvatar.setObjectName("pushButtonRemoveAvatar")
        self.groupBox_3 = QtWidgets.QGroupBox(parent=self.centralwidget)
        self.groupBox_3.setGeometry(QtCore.QRect(20, 40, 411, 191))
        self.groupBox_3.setStyleSheet("background-color: rgb(251, 255, 206);")
        self.groupBox_3.setObjectName("groupBox_3")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox_3)
        self.verticalLayout.setObjectName("verticalLayout")
        self.tableWidgetStudent = QtWidgets.QTableWidget(parent=self.groupBox_3)
        self.tableWidgetStudent.setStyleSheet("background-color: rgb(207, 255, 235);")
        self.tableWidgetStudent.setObjectName("tableWidgetStudent")
        self.tableWidgetStudent.setColumnCount(4)
        self.tableWidgetStudent.setRowCount(0)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetStudent.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetStudent.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetStudent.setHorizontalHeaderItem(2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidgetStudent.setHorizontalHeaderItem(3, item)
        self.verticalLayout.addWidget(self.tableWidgetStudent)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 456, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
        MainWindow.setTabOrder(self.tableWidgetStudent, self.lineEditCode)
        MainWindow.setTabOrder(self.lineEditCode, self.lineEditName)
        MainWindow.setTabOrder(self.lineEditName, self.lineEditAge)
        MainWindow.setTabOrder(self.lineEditAge, self.pushButtonNew)
        MainWindow.setTabOrder(self.pushButtonNew, self.pushButtonInsert)
        MainWindow.setTabOrder(self.pushButtonInsert, self.pushButtonRemove)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Trần Duy Thanh - Student Management"))
        self.label.setText(_translate("MainWindow", "Student Management"))
        self.groupBox.setTitle(_translate("MainWindow", "Actions:"))
        self.pushButtonRemove.setText(_translate("MainWindow", "Remove"))
        self.pushButtonInsert.setText(_translate("MainWindow", "Insert"))
        self.pushButtonNew.setText(_translate("MainWindow", "New"))
        self.pushButtonUpdate.setText(_translate("MainWindow", "Update"))
        self.groupBox_2.setTitle(_translate("MainWindow", "Student Details:"))
        self.label_4.setText(_translate("MainWindow", "Age:"))
        self.label_3.setText(_translate("MainWindow", "Name:"))
        self.label_2.setText(_translate("MainWindow", "Code:"))
        self.label_5.setText(_translate("MainWindow", "Intro:"))
        self.pushButtonAvatar.setText(_translate("MainWindow", "Avatar"))
        self.label_6.setText(_translate("MainWindow", "ID:"))
        self.pushButtonRemoveAvatar.setText(_translate("MainWindow", "Remove Avatar"))
        self.groupBox_3.setTitle(_translate("MainWindow", "List of Students:"))
        item = self.tableWidgetStudent.horizontalHeaderItem(0)
        item.setText(_translate("MainWindow", "ID"))
        item = self.tableWidgetStudent.horizontalHeaderItem(1)
        item.setText(_translate("MainWindow", "Code"))
        item = self.tableWidgetStudent.horizontalHeaderItem(2)
        item.setText(_translate("MainWindow", "Name"))
        item = self.tableWidgetStudent.horizontalHeaderItem(3)
        item.setText(_translate("MainWindow", "Age"))

Bước 4: Tạo MainWindowEx.py

Bước 4.1: Coding kế thừa Ui_MainWindow, và định nghĩa các biến như bên dưới:

import base64
import traceback
import mysql.connector
from PyQt6.QtGui import QPixmap
from PyQt6.QtWidgets import QTableWidgetItem, QFileDialog, QMessageBox
from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.default_avatar="images/ic_no_avatar.png"
        self.id = None
        self.code = None
        self.name = None
        self.age = None
        self.avatar = None
        self.intro = None

Bước 4.2: Override phương thức setupUI:

def setupUi(self, MainWindow):
    super().setupUi(MainWindow)
    self.MainWindow=MainWindow
    self.tableWidgetStudent.itemSelectionChanged.connect(self.processItemSelection)
    self.pushButtonAvatar.clicked.connect(self.pickAvatar)
    self.pushButtonRemoveAvatar.clicked.connect(self.removeAvatar)
    self.pushButtonInsert.clicked.connect(self.processInsert)
    self.pushButtonUpdate.clicked.connect(self.processUpdate)
    self.pushButtonRemove.clicked.connect(self.processRemove)
def show(self):
    self.MainWindow.show()

Hàm trên, ta thiết lập hàm nạp giao diện và khai báo các signals + slots

Bước 4.3: Viết mã lệnh kết nối MySQL Server, cơ sở dữ liệu studentmanagement (lưu ý nó là CSDL ở bài trước)

def connectMySQL(self):
    server = "localhost"
    port = 3306
    database = "studentmanagement"
    username = "root"
    password = "@Obama123"

    self.conn = mysql.connector.connect(
        host=server,
        port=port,
        database=database,
        user=username,
        password=password)

Bước 4.4: Viết lệnh truy vấn toàn bộ Student và hiển thị lên QTableWidget

def selectAllStudent(self):
    cursor = self.conn.cursor()
    # query all students
    sql = "select * from student"
    cursor.execute(sql)
    dataset = cursor.fetchall()
    self.tableWidgetStudent.setRowCount(0)
    row=0
    for item in dataset:
        row = self.tableWidgetStudent.rowCount()
        self.tableWidgetStudent.insertRow(row)

        self.id = item[0]
        self.code = item[1]
        self.name = item[2]
        self.age = item[3]
        self.avatar = item[4]
        self.intro = item[5]

        self.tableWidgetStudent.setItem(row, 0, QTableWidgetItem(str(self.id)))
        self.tableWidgetStudent.setItem(row, 1, QTableWidgetItem(self.code))
        self.tableWidgetStudent.setItem(row, 2, QTableWidgetItem(self.name))
        self.tableWidgetStudent.setItem(row, 3, QTableWidgetItem(str(self.age)))

    cursor.close()

Bước 4.5: Viết hàm hiển thị thông tin chi tiết student khi nhấn vào từng dòng dữ liệu trong QTableWidget

def processItemSelection(self):
    row=self.tableWidgetStudent.currentRow()
    if row ==-1:
        return
    try:
        code = self.tableWidgetStudent.item(row, 1).text()
        cursor = self.conn.cursor()
        # query all students
        sql = "select * from student where code=%s"
        val = (code,)
        cursor.execute(sql, val)
        item = cursor.fetchone()
        if item != None:
            self.id = item[0]
            self.code = item[1]
            self.name = item[2]
            self.age = item[3]
            self.avatar = item[4]
            self.intro = item[5]
            self.lineEditId.setText(str(self.id))
            self.lineEditCode.setText(self.code)
            self.lineEditName.setText(self.name)
            self.lineEditAge.setText(str(self.age))
            self.lineEditIntro.setText(self.intro)
            # self.labelAvatar.setPixmap(None)
            if self.avatar != None:
                imgdata = base64.b64decode(self.avatar)
                pixmap = QPixmap()
                pixmap.loadFromData(imgdata)
                self.labelAvatar.setPixmap(pixmap)
            else:
                pixmap = QPixmap("images/ic_no_avatar.png")

                self.labelAvatar.setPixmap(pixmap)
        else:
            print("Not Found")
        cursor.close()
    except:
        traceback.print_exc()

Bước 4.6: Viết lệnh chọn Avatar và xóa Avatar, có tạo base64string

def pickAvatar(self):
    filters = "Picture PNG (*.png);;All files(*)"
    filename, selected_filter = QFileDialog.getOpenFileName(
        self.MainWindow,
        filter=filters,
    )
    if filename=='':
        return
    pixmap = QPixmap(filename)
    self.labelAvatar.setPixmap(pixmap)

    with open(filename, "rb") as image_file:
        self.avatar = base64.b64encode(image_file.read())
        print(self.avatar)
    pass
def removeAvatar(self):
    self.avatar=None
    pixmap = QPixmap(self.default_avatar)
    self.labelAvatar.setPixmap(pixmap)

Bước 4.7: Viết hàm thêm mới Student:

def processInsert(self):
    try:
        cursor = self.conn.cursor()
        # query all students
        sql = "insert into student(Code,Name,Age,Avatar,Intro) values(%s,%s,%s,%s,%s)"

        self.code = self.lineEditCode.text()
        self.name = self.lineEditName.text()
        self.age = int(self.lineEditAge.text())
        if not hasattr(self, 'avatar'):
            avatar = None
        intro = self.lineEditIntro.text()
        val = (self.code, self.name, self.age, self.avatar, self.intro)

        cursor.execute(sql, val)

        self.conn.commit()

        print(cursor.rowcount, " record inserted")
        self.lineEditId.setText(str(cursor.lastrowid))

        cursor.close()
        self.selectAllStudent()
    except:
        traceback.print_exc()

Bước 4.8: Viết hàm cập nhật Student

def processUpdate(self):
    cursor = self.conn.cursor()
    # query all students
    sql = "update student set Code=%s,Name=%s,Age=%s,Avatar=%s,Intro=%s" \
          " where Id=%s"
    self.id=int(self.lineEditId.text())
    self.code = self.lineEditCode.text()
    self.name = self.lineEditName.text()
    self.age = int(self.lineEditAge.text())
    if not hasattr(self, 'avatar'):
        self.avatar = None
    self.intro = self.lineEditIntro.text()

    val = (self.code,self.name,self.age,self.avatar ,self.intro,self.id )

    cursor.execute(sql, val)

    self.conn.commit()

    print(cursor.rowcount, " record updated")
    cursor.close()
    self.selectAllStudent()

Bước 4.9: Viết hàm xóa Student:

def processRemove(self):
    dlg = QMessageBox(self.MainWindow)
    dlg.setWindowTitle("Confirmation Deleting")
    dlg.setText("Are you sure you want to delete?")
    dlg.setIcon(QMessageBox.Icon.Question)
    buttons = QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
    dlg.setStandardButtons(buttons)
    button = dlg.exec()
    if button == QMessageBox.StandardButton.No:
        return
    cursor = self.conn.cursor()
    # query all students
    sql = "delete from student "\
          " where Id=%s"

    val = (self.lineEditId.text(),)

    cursor.execute(sql, val)

    self.conn.commit()

    print(cursor.rowcount, " record removed")

    cursor.close()
    self.selectAllStudent()
    self.clearData()

Bước 4.10: Viết hàm xóa dữ liệu trên giao diện của phần chi tiết

def clearData(self):
    self.lineEditId.setText("")
    self.lineEditCode.setText("")
    self.lineEditName.setText("")
    self.lineEditAge.setText("")
    self.lineEditIntro.setText("")
    self.avatar=None

Dưới đây là mã lệnh đầy đủ của MainWindowEx.py:

import base64
import traceback
import mysql.connector
from PyQt6.QtGui import QPixmap
from PyQt6.QtWidgets import QTableWidgetItem, QFileDialog, QMessageBox
from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.default_avatar="images/ic_no_avatar.png"
        self.id = None
        self.code = None
        self.name = None
        self.age = None
        self.avatar = None
        self.intro = None
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        self.tableWidgetStudent.itemSelectionChanged.connect(self.processItemSelection)
        self.pushButtonAvatar.clicked.connect(self.pickAvatar)
        self.pushButtonRemoveAvatar.clicked.connect(self.removeAvatar)
        self.pushButtonInsert.clicked.connect(self.processInsert)
        self.pushButtonUpdate.clicked.connect(self.processUpdate)
        self.pushButtonRemove.clicked.connect(self.processRemove)
    def show(self):
        self.MainWindow.show()
    def connectMySQL(self):
        server = "localhost"
        port = 3306
        database = "studentmanagement"
        username = "root"
        password = "@Obama123"

        self.conn = mysql.connector.connect(
            host=server,
            port=port,
            database=database,
            user=username,
            password=password)
    def selectAllStudent(self):
        cursor = self.conn.cursor()
        # query all students
        sql = "select * from student"
        cursor.execute(sql)
        dataset = cursor.fetchall()
        self.tableWidgetStudent.setRowCount(0)
        row=0
        for item in dataset:
            row = self.tableWidgetStudent.rowCount()
            self.tableWidgetStudent.insertRow(row)

            self.id = item[0]
            self.code = item[1]
            self.name = item[2]
            self.age = item[3]
            self.avatar = item[4]
            self.intro = item[5]

            self.tableWidgetStudent.setItem(row, 0, QTableWidgetItem(str(self.id)))
            self.tableWidgetStudent.setItem(row, 1, QTableWidgetItem(self.code))
            self.tableWidgetStudent.setItem(row, 2, QTableWidgetItem(self.name))
            self.tableWidgetStudent.setItem(row, 3, QTableWidgetItem(str(self.age)))

        cursor.close()

    def processItemSelection(self):
        row=self.tableWidgetStudent.currentRow()
        if row ==-1:
            return
        try:
            code = self.tableWidgetStudent.item(row, 1).text()
            cursor = self.conn.cursor()
            # query all students
            sql = "select * from student where code=%s"
            val = (code,)
            cursor.execute(sql, val)
            item = cursor.fetchone()
            if item != None:
                self.id = item[0]
                self.code = item[1]
                self.name = item[2]
                self.age = item[3]
                self.avatar = item[4]
                self.intro = item[5]
                self.lineEditId.setText(str(self.id))
                self.lineEditCode.setText(self.code)
                self.lineEditName.setText(self.name)
                self.lineEditAge.setText(str(self.age))
                self.lineEditIntro.setText(self.intro)
                # self.labelAvatar.setPixmap(None)
                if self.avatar != None:
                    imgdata = base64.b64decode(self.avatar)
                    pixmap = QPixmap()
                    pixmap.loadFromData(imgdata)
                    self.labelAvatar.setPixmap(pixmap)
                else:
                    pixmap = QPixmap("images/ic_no_avatar.png")

                    self.labelAvatar.setPixmap(pixmap)
            else:
                print("Not Found")
            cursor.close()
        except:
            traceback.print_exc()

    def pickAvatar(self):
        filters = "Picture PNG (*.png);;All files(*)"
        filename, selected_filter = QFileDialog.getOpenFileName(
            self.MainWindow,
            filter=filters,
        )
        if filename=='':
            return
        pixmap = QPixmap(filename)
        self.labelAvatar.setPixmap(pixmap)

        with open(filename, "rb") as image_file:
            self.avatar = base64.b64encode(image_file.read())
            print(self.avatar)
        pass
    def removeAvatar(self):
        self.avatar=None
        pixmap = QPixmap(self.default_avatar)
        self.labelAvatar.setPixmap(pixmap)
    def processInsert(self):
        try:
            cursor = self.conn.cursor()
            # query all students
            sql = "insert into student(Code,Name,Age,Avatar,Intro) values(%s,%s,%s,%s,%s)"

            self.code = self.lineEditCode.text()
            self.name = self.lineEditName.text()
            self.age = int(self.lineEditAge.text())
            if not hasattr(self, 'avatar'):
                avatar = None
            intro = self.lineEditIntro.text()
            val = (self.code, self.name, self.age, self.avatar, self.intro)

            cursor.execute(sql, val)

            self.conn.commit()

            print(cursor.rowcount, " record inserted")
            self.lineEditId.setText(str(cursor.lastrowid))

            cursor.close()
            self.selectAllStudent()
        except:
            traceback.print_exc()

    def processUpdate(self):
        cursor = self.conn.cursor()
        # query all students
        sql = "update student set Code=%s,Name=%s,Age=%s,Avatar=%s,Intro=%s" \
              " where Id=%s"
        self.id=int(self.lineEditId.text())
        self.code = self.lineEditCode.text()
        self.name = self.lineEditName.text()
        self.age = int(self.lineEditAge.text())
        if not hasattr(self, 'avatar'):
            self.avatar = None
        self.intro = self.lineEditIntro.text()

        val = (self.code,self.name,self.age,self.avatar ,self.intro,self.id )

        cursor.execute(sql, val)

        self.conn.commit()

        print(cursor.rowcount, " record updated")
        cursor.close()
        self.selectAllStudent()
    def processRemove(self):
        dlg = QMessageBox(self.MainWindow)
        dlg.setWindowTitle("Confirmation Deleting")
        dlg.setText("Are you sure you want to delete?")
        dlg.setIcon(QMessageBox.Icon.Question)
        buttons = QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
        dlg.setStandardButtons(buttons)
        button = dlg.exec()
        if button == QMessageBox.StandardButton.No:
            return
        cursor = self.conn.cursor()
        # query all students
        sql = "delete from student "\
              " where Id=%s"

        val = (self.lineEditId.text(),)

        cursor.execute(sql, val)

        self.conn.commit()

        print(cursor.rowcount, " record removed")

        cursor.close()
        self.selectAllStudent()
        self.clearData()
    def clearData(self):
        self.lineEditId.setText("")
        self.lineEditCode.setText("")
        self.lineEditName.setText("")
        self.lineEditAge.setText("")
        self.lineEditIntro.setText("")
        self.avatar=None

Bước 5: Viết MyApp.py để thực thi phần mềm:

from PyQt6.QtWidgets import QApplication, QMainWindow

from MainWindowEx import MainWindowEx

app=QApplication([])
myWindow=MainWindowEx()
myWindow.setupUi(QMainWindow())
myWindow.connectMySQL()
myWindow.selectAllStudent()
myWindow.show()
app.exec()

Thực thi phần mềm ta có kết quả như mong muốn.

Đây là Case Study rất hay và quan trọng, làm nền tảng để làm các dự án khác, các bạn cố gắng thực hiện.

Source code đầy đủ của dự án bạn tải ở đây:

https://www.mediafire.com/file/c7x331c2pq5j4kp/StudentManagement.rar/file

Bài học tiếp theo Tui sẽ hướng dẫn các bạn cách mô hình hóa hướng đối tượng khi tương tác cơ sở dữ liệu

Chúc các bạn thành công

One thought on “Bài 49: Tương tác Python với Cơ sở dữ liệu MySQL Server -Quản lý Sinh viên”

Leave a Reply