Tutorial Python and PyMySQL database navigation
How to display MySQL database records in alphabetical order on a PyQT5 form regardless of record ID numbers
Introduction
Displaying records in order can be a bit tricky because records are usually not entered in alphabetical order, and using record IDs to control navigation doesn't work if ID numbers are not sequenced in increments of 1. This can happen if, for example, in a table that had ten records from 1 to 10, had records 3, 7 and 9 deleted, thus messing up the sequence.
The solution is to use row numbers, and this is how I did it:
- I designed a database navigation form on PyQT5 with four
QLineEdit
boxes and four navigation buttons: First, Previous, Next and Last. - Then I created a
FUNCTION
inphpMyAdmin
with a variable to generate the row numbers I will need in aVIEW
. TheFUNCTION
is as follows:DELIMITER $$ CREATE FUNCTION `row_numbers`() RETURNS INT(11) BEGIN SET @row_no := IFNULL(@row_no,0) + 1; RETURN @row_no; END$$ DELIMITER;
- Then I created a
VIEW
inphpMyAdmin
for a table called 'users
' to display the records in alphabetical order with their respective row numbers. TheVIEW
is as follows:CREATE VIEW users_view (number, name, email, pwd, market, id) AS SELECT row_numbers() AS number, name, email, pwd, market, id FROM users ORDER BY name
- And finally, here is the complete code for the navigation form in Python:
import sys import pymysql from PyQt5 import QtCore, QtWidgets from PyQt5.QtWidgets import QLineEdit from pymysql import Error rowNo = 1 connection = pymysql.connect(host='server_name_or_address', user='user_name', \ password='your_password', db='database_name') cur = connection.cursor() sql0 = "CREATE TEMPORARY TABLE users_temp AS SELECT number, name, email, pwd, \ market, id FROM users_view ORDER BY name" cur.execute(sql0) class Ui_Dialog(object): def __init__(self): self.lineEdit_name = QtWidgets.QLineEdit(Dialog) self.lineEdit_email = QtWidgets.QLineEdit(Dialog) self.lineEdit_pwd = QtWidgets.QLineEdit(Dialog) self.lineEdit_market = QtWidgets.QLineEdit(Dialog) self.pushButton_first = QtWidgets.QPushButton(Dialog) self.pushButton_previous = QtWidgets.QPushButton(Dialog) self.pushButton_next = QtWidgets.QPushButton(Dialog) self.pushButton_last = QtWidgets.QPushButton(Dialog) def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(448, 300) self.lineEdit_name.setGeometry(QtCore.QRect(130, 50, 241, 21)) self.lineEdit_name.setInputMethodHints(QtCore.Qt.ImhUppercaseOnly) self.lineEdit_name.setObjectName("lineEdit_name") self.lineEdit_email.setGeometry(QtCore.QRect(130, 90, 191, 21)) self.lineEdit_email.setInputMethodHints(QtCore.Qt.ImhEmailCharactersOnly) self.lineEdit_email.setObjectName("lineEdit_email") self.lineEdit_pwd.setGeometry(QtCore.QRect(130, 130, 131, 21)) self.lineEdit_pwd.setInputMethodHints (QtCore.Qt.ImhSensitiveData | QtCore.Qt.ImhUppercaseOnly) self.lineEdit_pwd.setObjectName("lineEdit_pwd") self.lineEdit_market.setGeometry(QtCore.QRect(130, 170, 131, 21)) self.lineEdit_market.setInputMethodHints(QtCore.Qt.ImhUppercaseOnly) self.lineEdit_market.setObjectName("lineEdit_market") self.pushButton_first.setGeometry(QtCore.QRect(70, 240, 61, 28)) self.pushButton_first.setObjectName("pushButton_first") self.pushButton_first.clicked.connect(ShowFirst) self.pushButton_previous.setGeometry(QtCore.QRect(150, 240, 61, 28)) self.pushButton_previous.setObjectName("pushButton_previous") self.pushButton_previous.clicked.connect(ShowPrevious) self.pushButton_next.setGeometry(QtCore.QRect(230, 240, 61, 28)) self.pushButton_next.setObjectName("pushButton_next") self.pushButton_next.clicked.connect(ShowNext) self.pushButton_last.setGeometry(QtCore.QRect(310, 240, 61, 28)) self.pushButton_last.setObjectName("pushButton_last") self.pushButton_last.clicked.connect(ShowLast) self.retranslateUi(Dialog) def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Usuários")) self.pushButton_first.setText(_translate("Dialog", "<<")) self.pushButton_previous.setText(_translate("Dialog", "<")) self.pushButton_next.setText(_translate("Dialog", ">")) self.pushButton_last.setText(_translate("Dialog", ">>")) LockForm(self) ShowFirst(self) def LockForm(self): for fields in Dialog.findChildren(QLineEdit): fields.setReadOnly(True) def ShowFirst(self): global rowNo sql = "SELECT number, name, email, pwd, market, id FROM users_temp" cur.execute(sql) row = cur.fetchone() if row: ui.lineEdit_name.setText(row[1]) ui.lineEdit_email.setText(row[2]) ui.lineEdit_pwd.setText(row[3]) ui.lineEdit_market.setText(row[4]) rowNo = row[0] else: print("Error in accessing table") def ShowPrevious(self): global rowNo rowNo -= 1 sql = "SELECT number, name, email, pwd, market, id FROM users_temp WHERE number=%s" cur.execute(sql, rowNo) row = cur.fetchone() if row: ui.lineEdit_name.setText(row[1]) ui.lineEdit_email.setText(row[2]) ui.lineEdit_pwd.setText(row[3]) ui.lineEdit_market.setText(row[4]) else: rowNo += 1 def ShowNext(self): global rowNo rowNo += 1 sql = "SELECT number, name, email, pwd, market, id FROM users_temp WHERE number=%s" cur.execute(sql, rowNo) row = cur.fetchone() if row: ui.lineEdit_name.setText(row[1]) ui.lineEdit_email.setText(row[2]) ui.lineEdit_pwd.setText(row[3]) ui.lineEdit_market.setText(row[4]) else: rowNo -= 1 def ShowLast(self): global rowNo sql = "SELECT number, name, email, pwd, market, id FROM users_temp" cur.execute(sql) for row in cur.fetchall(): ui.lineEdit_name.setText(row[1]) ui.lineEdit_email.setText(row[2]) ui.lineEdit_pwd.setText(row[3]) ui.lineEdit_market.setText(row[4]) rowNo = row[0] if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) Dialog = QtWidgets.QDialog() ui = Ui_Dialog() ui.setupUi(Dialog) Dialog.show() sys.exit(app.exec_())
That's it, guys! I hope it helps. Best regards and stay well.
History
- 11th April, 2020: Initial version