PyQt5快速入門(八)PyQt5數據庫操作
一、SQLite數據庫
1、SQLite簡介
SQLite是一個輕量級的數據庫,實現了自給自足、無服務器、零配置、事務性的SQL數據庫引擎,主要作爲手機應用的數據庫以及小型桌面應用的數據庫。
官方網站:
https://www.sqlite.org
2、SQLite常用操作
創建數據庫文件,創建後進行入SQLite命令行模式。sqlite3 DatabaseName.db
查看已經存在的數據庫文件,在SQLite命令行模式執行:.databases
打開已經存在的數據庫文件,如果數據庫文件不存在,則創建。sqlite3 DatabaseName.db
查看幫助信息,在SQLite命令行模式執行:.help
創建表,在SQLite命令行模式執行:create table person(id integer primary key, name text);
插入數據到表:insert into person(id, name) values(1, "zhangsan");
查詢操作:select * from person;
查詢表的結構:.schema person
3、SQLite管理工具
SQLite有多個開源且優秀的DBMS(數據庫管理系統),提供了界面操作SQLite數據庫。
SQLiteStudio是一款非常專業的SQLite數據庫管理軟件,體積小巧,功能強大,支持中文,免安裝。
SQLiteStudio下載:
https://sqlitestudio.pl/index.rvt?act=download
二、連接數據庫
1、數據庫驅動類型
PyQt中,QSqlDatabase類用於連接數據庫,可以使用數據庫驅動與不同的數據庫進行交互,一個QSqlDatabase實例代表一次數據庫連接。可用數據庫驅動類型如下:
QDB2 IBM DB2驅動程序
QMYSQL MySQL驅動程序
QOCI Oracle調用接口驅動程序
QODBC ODBC驅動程序(包括MS SQL Server)
QPSQL PostgreSQL驅動程序
QSQLITE SQLite3驅動程序
QSQLITE2 SQLite2驅動程序
2、QSqlDatabase常用方法
QSqlDatabase常用方法如下:
addDataBase:設置連接數據庫的數據庫驅動類型
setDatabaseName:設置所連接的數據庫名稱
setHostName:設置數據庫所在的主機名稱
setUserName:指定連接的用戶名
setPassword:設置連接對象的密碼
commit:提交事務,如果執行成功返回True。
rollback:回滾數據庫事務
close:關閉數據庫連接
3、數據庫連接實例
import sys
from PyQt5.QtSql import QSqlDatabase
from PyQt5.QtCore import *
if __name__ == "__main__":
app = QCoreApplication(sys.argv)
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("/home/user/test.db")
if db.open():
print("open DB success.")
sys.exit(app.exec_())
三、執行SQL語句
QSqlQuery具有執行和操作SQL語句的功能,可以執行DDL和DML類型的SQL查詢,QSqlQuery.exec_()
用於執行SQL操作。
import sys
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
from PyQt5.QtCore import *
def createDB():
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("/home/user/test.db")
if db.open():
query = QSqlQuery()
query.exec_("create table person(id int primary key, name varchar(20), address varchar(30))")
query.exec_("insert into person values(1, 'Bauer', 'beijing')")
query.exec_("insert into person values(2, 'Jack', 'shanghai')")
query.exec_("insert into person values(3, 'Alex', 'chengdu')")
db.close()
if __name__ == "__main__":
app = QCoreApplication(sys.argv)
createDB()
sys.exit(app.exec_())
執行完SQL語句後,如果沒有其它數據庫操作,需要使用db.close關閉數據庫連接,因爲數據庫連接資源是有限的,不再使用的數據庫連接必須關閉,否則數據庫連接資源最終會被耗盡,導致程序無法正常連接數據庫。
如果在PyQt的窗口中需要讀取數據庫的數據並進行顯示,則需要在窗口初始化時打開數據庫,在窗口關閉時關閉數據庫連接。
import sys
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.db = QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName("/home/user/test.db")
self.db.open()
def closeEvent(self, event):
self.db.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
四、數據庫模型視圖
Qt中的QSqlTableModel是一個高級接口,提供了可讀可寫的數據模型,用於在單個表中讀取和保存數據,可以在QTableView展示數據庫的表格。當連接到數據庫後,使用seTable設置要查詢的表,使用setFilter函數設置過濾器條件,然後使用select函數進行查詢操作。可以使用setEditerStrategy函數設置編輯策略,可設置編輯策略如下:
QSqlTableModel.OnFieldChange:所有變更實時更新到數據庫
QSqlTableModel.OnRowChange:當用戶選擇不同的行時,在當前行進行更新
QSqlTableModel.OnManuallSubmit:手動提交,不自動提交
import sys
from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlTableModel
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.db = QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName("/home/user/test.db")
self.db.open()
self.model = QSqlTableModel()
self.initializedModel()
self.tableView = QTableView()
self.tableView.setModel(self.model)
self.layout = QVBoxLayout()
addButton = QPushButton("add")
deleteButton = QPushButton("delete")
hLayout = QHBoxLayout()
hLayout.addWidget(addButton)
hLayout.addWidget(deleteButton)
self.layout.addWidget(self.tableView)
self.layout.addLayout(hLayout)
self.setLayout(self.layout)
self.resize(600, 400)
addButton.clicked.connect(self.onAddRow)
deleteButton.clicked.connect(self.onDeleteRow)
def initializedModel(self):
self.model.setTable("person")
self.model.setEditStrategy(QSqlTableModel.OnFieldChange)
self.model.select()
self.model.setHeaderData(0, Qt.Horizontal, "ID")
self.model.setHeaderData(1, Qt.Horizontal, "Name")
self.model.setHeaderData(2, Qt.Horizontal, "Address")
def onAddRow(self):
self.model.insertRows(self.model.rowCount(), 1)
self.model.submit()
def onDeleteRow(self):
self.model.removeRow(self.tableView.currentIndex().row())
self.model.submit()
self.model.select()
def closeEvent(self, event):
self.db.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
五、分頁查詢
1、數據準備
分頁使用數據爲學生信息student表,可以使用SQLite命令行使用SQL語句插入,也可以使用Python程序創建表並插入數據。
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("/home/user/test.db")
if not db.open():
return False
query = QSqlQuery()
query.exec_("create table student(id int primary key, name varchar(20), sex varchar(8), age int);")
query.exec_("insert into student values(1, 'Bauer', 'Man', 25)")
query.exec_("insert into student values(2, 'Alex', 'Man', 24)")
query.exec_("insert into student values(3, 'Mary', 'Female', 23)")
query.exec_("insert into student values(4, 'Jack', 'Man', 25)")
query.exec_("insert into student values(5, 'xiaoming', 'Man', 24)")
query.exec_("insert into student values(6, 'xiaohong', 'Female', 23)")
query.exec_("insert into student values(7, 'xiaowang', 'Man', 25)")
query.exec_("insert into student values(8, 'xiaozhang', 'Man', 25)")
query.exec_("insert into student values(9, 'xiaoli', 'Man', 25)")
query.exec_("insert into student values(10, 'xiaohan', 'Man', 25)")
2、分頁窗口
分頁窗口包括標籤、前一頁、後一頁、跳轉按鈕等。
import sys
from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlTableModel, QSqlQueryModel
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class DataGrid(QWidget):
def __init__(self, parent=None):
super(DataGrid, self).__init__(parent)
# 數據庫連接
self.db = None
# 佈局管理器
self.layout = QVBoxLayout()
# 查詢模型
self.queryModel = QSqlQueryModel()
# 表格視圖
self.tableView = QTableView()
self.tableView.setModel(self.queryModel)
#
self.totalPageLabel = QLabel()
self.currentPageLabel = QLabel()
self.switchPageLineEdit = QLineEdit()
self.prevButton = QPushButton("Prev")
self.nextButton = QPushButton("Next")
self.switchPageButton = QPushButton("Switch")
self.currentPage = 0
self.totalPage = 0
self.totalRecordCount = 0
self.pageRecordCount = 5
def initUI(self):
self.tableView.horizontalHeader().setStretchLastSection(True)
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.layout.addWidget(self.tableView)
hLayout = QHBoxLayout()
hLayout.addWidget(self.prevButton)
hLayout.addWidget(self.nextButton)
hLayout.addWidget(QLabel("跳轉到"))
self.switchPageLineEdit.setFixedWidth(40)
hLayout.addWidget(self.switchPageLineEdit)
hLayout.addWidget(QLabel("頁"))
hLayout.addWidget(self.switchPageButton)
hLayout.addWidget(QLabel("當前頁:"))
hLayout.addWidget(self.currentPageLabel)
hLayout.addWidget(QLabel("總頁數:"))
hLayout.addWidget(self.totalPageLabel)
hLayout.addStretch(1)
self.layout.addLayout(hLayout)
self.setLayout(self.layout)
self.setWindowTitle("DataGrid")
self.resize(600, 300)
def closeEvent(self, event):
self.db.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = DataGrid()
window.initUI()
window.show()
sys.exit(app.exec_())
3、分頁查詢實現
讀取數據庫的student表,初始化表格數據模型。
import sys
from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlTableModel, QSqlQueryModel
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import re
class DataGrid(QWidget):
def __init__(self, parent=None):
super(DataGrid, self).__init__(parent)
# 聲明數據庫連接
self.db = None
# 佈局管理器
self.layout = QVBoxLayout()
# 查詢模型
self.queryModel = QSqlQueryModel()
# 表格視圖
self.tableView = QTableView()
self.tableView.setModel(self.queryModel)
#
self.totalPageLabel = QLabel()
self.currentPageLabel = QLabel()
self.switchPageLineEdit = QLineEdit()
self.prevButton = QPushButton("Prev")
self.nextButton = QPushButton("Next")
self.switchPageButton = QPushButton("Switch")
# 當前頁
self.currentPage = 1
# 總頁數
self.totalPage = None
# 總記錄數
self.totalRecordCount = None
# 每頁記錄數
self.pageRecordCount = 4
self.initUI()
self.initializedModel()
self.setUpConnect()
self.updateStatus()
def initUI(self):
self.tableView.horizontalHeader().setStretchLastSection(True)
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.layout.addWidget(self.tableView)
hLayout = QHBoxLayout()
hLayout.addWidget(self.prevButton)
hLayout.addWidget(self.nextButton)
hLayout.addWidget(QLabel("跳轉到"))
self.switchPageLineEdit.setFixedWidth(40)
hLayout.addWidget(self.switchPageLineEdit)
hLayout.addWidget(QLabel("頁"))
hLayout.addWidget(self.switchPageButton)
hLayout.addWidget(QLabel("當前頁:"))
hLayout.addWidget(self.currentPageLabel)
hLayout.addWidget(QLabel("總頁數:"))
hLayout.addWidget(self.totalPageLabel)
hLayout.addStretch(1)
self.layout.addLayout(hLayout)
self.setLayout(self.layout)
self.setWindowTitle("DataGrid")
self.resize(600, 300)
def setUpConnect(self):
self.prevButton.clicked.connect(self.onPrevPage)
self.nextButton.clicked.connect(self.onNextPage)
self.switchPageButton.clicked.connect(self.onSwitchPage)
def initializedModel(self):
self.db = QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName("/home/user/test.db")
if not self.db.open():
return False
self.queryModel.setHeaderData(0, Qt.Horizontal, "ID")
self.queryModel.setHeaderData(1, Qt.Horizontal, "Name")
self.queryModel.setHeaderData(2, Qt.Horizontal, "Sex")
self.queryModel.setHeaderData(3, Qt.Horizontal, "Age")
# 獲取表的所有記錄數
sql = "SELECT * FROM student"
self.queryModel.setQuery(sql, self.db)
self.totalRecordCount = self.queryModel.rowCount()
if self.totalRecordCount % self.pageRecordCount == 0:
self.totalPage = self.totalRecordCount / self.pageRecordCount
else:
self.totalPage = int(self.totalRecordCount / self.pageRecordCount) + 1
# 顯示第1頁
sql = "SELECT * FROM student limit %d,%d" % (0, self.pageRecordCount)
self.queryModel.setQuery(sql, self.db)
def onPrevPage(self):
self.currentPage -= 1
limitIndex = (self.currentPage - 1) * self.pageRecordCount
self.queryRecord(limitIndex)
self.updateStatus()
def onNextPage(self):
self.currentPage += 1
limitIndex = (self.currentPage - 1) * self.pageRecordCount
self.queryRecord(limitIndex)
self.updateStatus()
def onSwitchPage(self):
szText = self.switchPageLineEdit.text()
pattern = re.compile('^[0-9]+$')
match = pattern.match(szText)
if not match:
QMessageBox.information(self, "提示", "請輸入數字.")
return
if szText == "":
QMessageBox.information(self, "提示", "請輸入跳轉頁面.")
return
pageIndex = int(szText)
if pageIndex > self.totalPage or pageIndex < 1:
QMessageBox.information(self, "提示", "沒有指定的頁,清重新輸入.")
return
limitIndex = (pageIndex - 1) * self.pageRecordCount
self.queryRecord(limitIndex)
self.currentPage = pageIndex
self.updateStatus()
# 根據分頁查詢記錄
def queryRecord(self, limitIndex):
sql = "SELECT * FROM student limit %d,%d" % (limitIndex, self.pageRecordCount)
self.queryModel.setQuery(sql)
# 更新空間狀態
def updateStatus(self):
self.currentPageLabel.setText(str(self.currentPage))
self.totalPageLabel.setText(str(self.totalPage))
if self.currentPage <= 1:
self.prevButton.setEnabled(False)
else:
self.prevButton.setEnabled(True)
if self.currentPage >= self.totalPage:
self.nextButton.setEnabled(False)
else:
self.nextButton.setEnabled(True)
# 界面關閉時關閉數據庫連接
def closeEvent(self, event):
self.db.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = DataGrid()
window.show()
sys.exit(app.exec_())