什么是SQLite
SQLite是一个轻量级的数据库,实现了自给自足、无服务器、零配置、事务性的 SOL 数据库引擎,其部署最广泛。SQLite 源代码不受版权限制。
安装并使用SQLite


配置环境变量


安装完成
SQLite常用操作
新建数据库

查看已建立的数据库文件

打开已建立的数据库文件

若数据库文件不存在,则会自动新建数据库文件
查看帮助信息

创建表
create table people(id integer primary key,name text);
插入数据

查询

开启表头

查看表结构

使用SQLite管理工具
这里笔者使用Navicat 15


PyQt APl 经过精心设计,提供了很多基于SQL 的数据库通信类。其中QSqIDatabase类用来连接数据库,可以使用数据库驱动(Driver)与不同的数据库进行交互。一个OSqlDatabase实例代表了一次数据库连接。
数据库驱动类型:
| 数据库驱动类型 | 描述 |
|---|---|
| QDB2 | IBM DB2驱动程序 |
| QIBASE | Borland InterBase驱动程序 |
| QMYSQL | MySQL驱动程序 |
| QOCI | Oracle调用接口驱动程序 |
| QODBC | ODBC驱动程序(包含Microsoft SQL Server) |
| QPSQL | PostgreSQL驱动程序 |
| QSQLITE | SQLite3或更高版本的驱动程序 |
| QSQLITE2 | SQLite2驱动程序 |
QSqlDatabase类中的常用方法
| 方法 | 描述 |
|---|---|
| addDatabase() | 设置连接数据库的数据库驱动类型 |
| setDatabaseName() | 设置所连接的数据库名称 |
| setHostName() | 设置安装数据库的主机名称 |
| setUserName() | 指定连接的用户名 |
| setPassword() | 设置连接对象的密码(如果有) |
| commit() | 提交事务,如果执行成功则返回True |
| rollback() | 回滚数据库事务 |
| close() | 关闭数据库连接 |
案例——使用QSqlDatabase连接MySQL数据库、SQLite数据库
from PyQt5.QtSql import QSqlDatabase
db = QSqlDatabase.addDatabase("QMYSQL")
db.setHostName("127.0.0.1")
db.setDatabaseName("pyqt")
db.setUserName("root")
db.setPassword("200039")
dbConn = db.open()
连接到SQLite数据库
from PyQt5.QtSql import QSqlDatabase
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName('E:\\SQLiteDatabases\\testDb.db')
dbConn = db.open()
QSqlQuery类具有执行和操作SQL语句的功能,可以执行 DDL 和 DML类型的SQL查询。
该类中最重要的方法是exec_(),它将一个包含要执行的SQL语句的字符串作为参数。
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtSql import QSqlDatabase , QSqlQuery
def createDB():
db = QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('db/database.db')
if not db.open():
QMessageBox.critical(None , ("无法打开数据库"),("无法建立连接,单击取消退出"),
QMessageBox.Cancel)
return False
query = QSqlQuery()
query.exec_("create table people(id int primary key ,name varchar(20) ,address varchar(30))")
query.exec_("insert into people values (1,'zhangsan1','BeiJing')")
query.exec_("insert into people values (2,'lisi1','TianJin')")
query.exec_("insert into people values (3,'wangwu1','HeNan')")
query.exec_("insert into people values (4,'lisi2','HeBei')")
query.exec_("insert into people values (5,'wangwu2','ShangHai')")
# 关闭数据库
db.close()
return True
if __name__ == '__main__':
app = QApplication(sys.argv)
createDB()
sys.exit(app.exec_())


成功连接并处理
PyQt中的 QSqITableModel类是一个高级接口,提供了可读的数据模型,用在单个表中读取和保存数据。此模型用于填充QTableView对象,它向用户呈现了可以放在任何顶层窗口中的可滚动和可编辑的视图。
QSqITableModel类是一个可以读和写的表格模型,当连接到数据库后,使用setTable()函数设置要查询的表,使用setFilter()函数设置过滤器条件,这个过滤器条件与SQL查询语句中的where条件一样,然后使用select()函数执行查询,最后使用setEditStrategy()函数设置“编辑策略”。
可设置的编辑策略:
| 编辑策略 | 描述 |
|---|---|
| QSqlTableModel.OnFieldChange | 所有变更实时更新到数据库中 |
| QSqlTableModel.OnRowChange | 当用户选择不同的行时,在当前行进行更改 |
| QSqlTableModel.OnManualSubmit | 手动提交,不自动提交 |
案例
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtSql import QSqlDatabase, QSqlTableModel
from PyQt5.QtCore import Qt
def initializeModel(model):
model.setTable('people')
model.setEditStrategy(QSqlTableModel.OnFieldChange)
model.select()
model.setHeaderData(0, Qt.Horizontal, "ID")
model.setHeaderData(1, Qt.Horizontal, "name")
model.setHeaderData(2, Qt.Horizontal, "address")
def createView(title, model):
view = QTableView()
view.setModel(model)
view.setWindowTitle(title)
return view
def addrow():
ret = model.insertRows(model.rowCount(), 1)
print('insertRows=%s' % str(ret))
def findrow(i):
delrow = i.row()
print('del row=%s' % str(delrow))
if __name__ == '__main__':
app = QApplication(sys.argv)
db = QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('db/database.db')
model = QSqlTableModel()
delrow = -1
initializeModel(model)
view1 = createView("Table Model (View 1)", model)
view1.clicked.connect(findrow)
dlg = QDialog()
layout = QVBoxLayout()
layout.addWidget(view1)
addBtn = QPushButton("添加一行")
addBtn.clicked.connect(addrow)
layout.addWidget(addBtn)
delBtn = QPushButton("删除一行")
delBtn.clicked.connect(lambda: model.removeRow(view1.currentIndex().row()))
layout.addWidget(delBtn)
dlg.setLayout(layout)
dlg.setWindowTitle("Database 例子")
dlg.resize(430, 450)
dlg.show()
sys.exit(app.exec_())

准备分页数据
CREATE TABLE "student" (
"id" int,
"name" vchar,
"sex" vchar,
"age" int,
"deparment" vchar,
PRIMARY KEY ("id")
);
INSERT INTO "student" VALUES (1, '张三1', '男', 20, '计算机');
INSERT INTO "student" VALUES (2, '李四1', '男', 19, '经管');
INSERT INTO "student" VALUES (3, '王五1', '男', 22, '机械');
INSERT INTO "student" VALUES (4, '赵六1', '男', 21, '法律');
INSERT INTO "student" VALUES (5, '小明1', '男', 20, '英语');
INSERT INTO "student" VALUES (6, '小李1', '女', 19, '计算机');
INSERT INTO "student" VALUES (7, '小张1', '男', 20, '机械');
INSERT INTO "student" VALUES (8, '小刚1', '男', 19, '经管');
INSERT INTO "student" VALUES (9, '张三2', '男', 21, '计算机');
INSERT INTO "student" VALUES (10, '张三3', '女', 20, '法律');
INSERT INTO "student" VALUES (11, '王五2', '男', 19, '经管');
INSERT INTO "student" VALUES (12, '张三4', '男', 20, '计算机');
INSERT INTO "student" VALUES (13, '小李2', '男', 20, '机械');
INSERT INTO "student" VALUES (14, '李四2', '女', 19, '经管');
INSERT INTO "student" VALUES (15, '赵六3', '男', 21, '英语');
INSERT INTO "student" VALUES (16, '李四2', '男', 19, '法律');
INSERT INTO "student" VALUES (17, '小张2', '女', 22, '经管');
INSERT INTO "student" VALUES (18, '李四3', '男', 21, '英语');
INSERT INTO "student" VALUES (19, '小李3', '女', 19, '法律');
INSERT INTO "student" VALUES (20, '王五3', '女', 20, '机械');
INSERT INTO "student" VALUES (21, '张三4', '男', 22, '计算机');
INSERT INTO "student" VALUES (22, '小李2', '男', 20, '法律');
INSERT INTO "student" VALUES (23, '张三5', '男', 19, '经管');
INSERT INTO "student" VALUES (24, '小张3', '女', 20, '计算机');
INSERT INTO "student" VALUES (25, '李四4', '男', 22, '英语');
INSERT INTO "student" VALUES (26, '赵六2', '男', 20, '机械');
INSERT INTO "student" VALUES (27, '小李3', '女', 19, '英语');
INSERT INTO "student" VALUES (28, '王五4', '男', 21, '经管');

创建分页窗口控件
DataGrid.py
from PyQt5.QtWidgets import QWidget
class DataGrid(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("分页查询例子")
self.resize(750, 300)
# 查询模型
self.queryModel = None
# 数据表
self.tableView = None
# 总数页文本
self.totalPageLabel = None
# 当前页文本
self.currentPageLabel = None
# 转到页输入框
self.switchPageLineEdit = None
# 前一页按钮
self.prevButton = None
# 后一页按钮
self.nextButton = None
# 转到页按钮
self.switchPageButton = None
# 当前页
self.currentPage = 0
# 总页数
self.totalPage = 0
# 总记录数
self.totalRecrodCount = 0
# 每页显示记录数
self.PageRecordCount = 5
创建窗口
def createWindow(self):
# 操作布局
operatorLayout = QHBoxLayout()
self.prevButton = QPushButton("前一页")
self.nextButton = QPushButton("后一页")
self.switchPageButton = QPushButton("Go")
self.switchPageLineEdit = QLineEdit()
self.switchPageLineEdit.setFixedWidth(40)
switchPage = QLabel("转到第")
page = QLabel("页")
operatorLayout.addWidget(self.prevButton)
operatorLayout.addWidget(self.nextButton)
operatorLayout.addWidget(switchPage)
operatorLayout.addWidget(self.switchPageLineEdit)
operatorLayout.addWidget(page)
operatorLayout.addWidget(self.switchPageButton)
operatorLayout.addWidget( QSplitter())
# 状态布局
statusLayout = QHBoxLayout()
self.totalPageLabel = QLabel()
self.totalPageLabel.setFixedWidth(70)
self.currentPageLabel = QLabel()
self.currentPageLabel.setFixedWidth(70)
self.totalRecordLabel = QLabel()
self.totalRecordLabel.setFixedWidth(70)
statusLayout.addWidget(self.totalPageLabel)
statusLayout.addWidget(self.currentPageLabel)
statusLayout.addWidget( QSplitter() )
statusLayout.addWidget(self.totalRecordLabel)
# 设置表格属性
self.tableView = QTableView()
# 表格宽度的自适应调整
self.tableView.horizontalHeader().setStretchLastSection(True)
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
# 创建界面
mainLayout = QVBoxLayout(self);
mainLayout.addLayout(operatorLayout);
mainLayout.addWidget(self.tableView);
mainLayout.addLayout(statusLayout);
self.setLayout(mainLayout)
获得表格控件用到的数据
def setTableView(self):
print('*** step2 SetTableView' )
self.db = QSqlDatabase.addDatabase('QSQLITE')
# 设置数据库名称
self.db.setDatabaseName('/db/database.db')
# 打开数据库
self.db.open()
# 声明查询模型
self.queryModel = QSqlQueryModel(self)
# 设置当前页
self.currentPage = 1;
# 得到总记录数
self.totalRecrodCount = self.getTotalRecordCount()
# 得到总页数
self.totalPage = self.getPageCount()
# 刷新状态
self.updateStatus()
# 设置总页数文本
self.setTotalPageLabel()
# 设置总记录数
self.setTotalRecordLabel()
# 记录查询
self.recordQuery(0)
# 设置模型
self.tableView.setModel(self.queryModel)
print('totalRecrodCount=' + str(self.totalRecrodCount) )
print('totalPage=' + str(self.totalPage) )
# 设置表格表头
self.queryModel.setHeaderData(0,Qt.Horizontal,"编号")
self.queryModel.setHeaderData(1,Qt.Horizontal,"姓名")
self.queryModel.setHeaderData(2,Qt.Horizontal,"性别")
self.queryModel.setHeaderData(3,Qt.Horizontal,"年龄")
self.queryModel.setHeaderData(4,Qt.Horizontal,"院系")
运行测试

完整代码
# -*- coding: utf-8 -*-
import sys
import re
from PyQt5.QtWidgets import (QWidget, QHBoxLayout, QVBoxLayout, QApplication, QPushButton, QLineEdit, QLabel, QSplitter,
QTableView, QHeaderView, QMessageBox)
from PyQt5.QtCore import Qt
from PyQt5.QtSql import QSqlDatabase, QSqlQueryModel, QSqlQuery
def createTableAndInit():
# 添加数据库
db = QSqlDatabase.addDatabase('QSQLITE')
# 设置数据库名称
db.setDatabaseName('db/database.db')
# 判断是否打开
if not db.open():
return False
# 声明数据库查询对象
query = QSqlQuery()
# # 创建表
# query.exec("create table student(id int primary key, name vchar, sex vchar, age int, deparment vchar)")
#
# #添加记录
# query.exec("insert into student values(1,'张三1','男',20,'计算机')")
# query.exec("insert into student values(2,'李四1','男',19,'经管')")
# query.exec("insert into student values(3,'王五1','男',22,'机械')")
# query.exec("insert into student values(4,'赵六1','男',21,'法律')")
# query.exec("insert into student values(5,'小明1','男',20,'英语')")
# query.exec("insert into student values(6,'小李1','女',19,'计算机')")
# query.exec("insert into student values(7,'小张1','男',20,'机械')")
# query.exec("insert into student values(8,'小刚1','男',19,'经管')")
# query.exec("insert into student values(9,'张三2','男',21,'计算机')")
# query.exec("insert into student values(10,'张三3','女',20,'法律')")
# query.exec("insert into student values(11,'王五2','男',19,'经管')")
# query.exec("insert into student values(12,'张三4','男',20,'计算机')")
# query.exec("insert into student values(13,'小李2','男',20,'机械')")
# query.exec("insert into student values(14,'李四2','女',19,'经管')")
# query.exec("insert into student values(15,'赵六3','男',21,'英语')")
# query.exec("insert into student values(16,'李四2','男',19,'法律')")
# query.exec("insert into student values(17,'小张2','女',22,'经管')")
# query.exec("insert into student values(18,'李四3','男',21,'英语')")
# query.exec("insert into student values(19,'小李3','女',19,'法律')")
# query.exec("insert into student values(20,'王五3','女',20,'机械')")
# query.exec("insert into student values(21,'张三4','男',22,'计算机')")
# query.exec("insert into student values(22,'小李2','男',20,'法律')")
# query.exec("insert into student values(23,'张三5','男',19,'经管')")
# query.exec("insert into student values(24,'小张3','女',20,'计算机')")
# query.exec("insert into student values(25,'李四4','男',22,'英语')")
# query.exec("insert into student values(26,'赵六2','男',20,'机械')")
# query.exec("insert into student values(27,'小李3','女',19,'英语')")
# query.exec("insert into student values(28,'王五4','男',21,'经管')")
db.close()
return True
class DataGrid(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("分页查询例子")
self.resize(750, 300)
# 查询模型
self.queryModel = None
# 数据表
self.tableView = None
# 总数页文本
self.totalPageLabel = None
# 当前页文本
self.currentPageLabel = None
# 转到页输入框
self.switchPageLineEdit = None
# 前一页按钮
self.prevButton = None
# 后一页按钮
self.nextButton = None
# 转到页按钮
self.switchPageButton = None
# 当前页
self.currentPage = 0
# 总页数
self.totalPage = 0
# 总记录数
self.totalRecrodCount = 0
# 每页显示记录数
self.PageRecordCount = 5
self.db = None
self.initUI()
def initUI(self):
# 创建窗口
self.createWindow()
# 设置表格
self.setTableView()
# 信号槽连接
self.prevButton.clicked.connect(self.onPrevButtonClick)
self.nextButton.clicked.connect(self.onNextButtonClick)
self.switchPageButton.clicked.connect(self.onSwitchPageButtonClick)
def closeEvent(self, event):
# 关闭数据库
self.db.close()
# 创建窗口
def createWindow(self):
# 操作布局
operatorLayout = QHBoxLayout()
self.prevButton = QPushButton("前一页")
self.nextButton = QPushButton("后一页")
self.switchPageButton = QPushButton("Go")
self.switchPageLineEdit = QLineEdit()
self.switchPageLineEdit.setFixedWidth(40)
switchPage = QLabel("转到第")
page = QLabel("页")
operatorLayout.addWidget(self.prevButton)
operatorLayout.addWidget(self.nextButton)
operatorLayout.addWidget(switchPage)
operatorLayout.addWidget(self.switchPageLineEdit)
operatorLayout.addWidget(page)
operatorLayout.addWidget(self.switchPageButton)
operatorLayout.addWidget(QSplitter())
# 状态布局
statusLayout = QHBoxLayout()
self.totalPageLabel = QLabel()
self.totalPageLabel.setFixedWidth(70)
self.currentPageLabel = QLabel()
self.currentPageLabel.setFixedWidth(70)
self.totalRecordLabel = QLabel()
self.totalRecordLabel.setFixedWidth(70)
statusLayout.addWidget(self.totalPageLabel)
statusLayout.addWidget(self.currentPageLabel)
statusLayout.addWidget(QSplitter())
statusLayout.addWidget(self.totalRecordLabel)
# 设置表格属性
self.tableView = QTableView()
# 表格宽度的自适应调整
self.tableView.horizontalHeader().setStretchLastSection(True)
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
# 创建界面
mainLayout = QVBoxLayout(self);
mainLayout.addLayout(operatorLayout);
mainLayout.addWidget(self.tableView);
mainLayout.addLayout(statusLayout);
self.setLayout(mainLayout)
# 设置表格
def setTableView(self):
print('*** step2 SetTableView')
self.db = QSqlDatabase.addDatabase('QSQLITE')
# 设置数据库名称
self.db.setDatabaseName('db/database.db')
# 打开数据库
self.db.open()
# 声明查询模型
self.queryModel = QSqlQueryModel(self)
# 设置当前页
self.currentPage = 1;
# 得到总记录数
self.totalRecrodCount = self.getTotalRecordCount()
# 得到总页数
self.totalPage = self.getPageCount()
# 刷新状态
self.updateStatus()
# 设置总页数文本
self.setTotalPageLabel()
# 设置总记录数
self.setTotalRecordLabel()
# 记录查询
self.recordQuery(0)
# 设置模型
self.tableView.setModel(self.queryModel)
print('totalRecrodCount=' + str(self.totalRecrodCount))
print('totalPage=' + str(self.totalPage))
# 设置表格表头
self.queryModel.setHeaderData(0, Qt.Horizontal, "编号")
self.queryModel.setHeaderData(1, Qt.Horizontal, "姓名")
self.queryModel.setHeaderData(2, Qt.Horizontal, "性别")
self.queryModel.setHeaderData(3, Qt.Horizontal, "年龄")
self.queryModel.setHeaderData(4, Qt.Horizontal, "院系")
# 得到记录数
def getTotalRecordCount(self):
self.queryModel.setQuery("select * from student")
rowCount = self.queryModel.rowCount()
print('rowCount=' + str(rowCount))
return rowCount
# 得到页数
def getPageCount(self):
if self.totalRecrodCount % self.PageRecordCount == 0:
return (self.totalRecrodCount / self.PageRecordCount)
else:
return (self.totalRecrodCount / self.PageRecordCount + 1)
# 记录查询
def recordQuery(self, limitIndex):
szQuery = ("select * from student limit %d,%d" % (limitIndex, self.PageRecordCount))
print('query sql=' + szQuery)
self.queryModel.setQuery(szQuery)
# 刷新状态
def updateStatus(self):
szCurrentText = ("当前第%d页" % self.currentPage)
self.currentPageLabel.setText(szCurrentText)
# 设置按钮是否可用
if self.currentPage == 1:
self.prevButton.setEnabled(False)
self.nextButton.setEnabled(True)
elif self.currentPage == self.totalPage:
self.prevButton.setEnabled(True)
self.nextButton.setEnabled(False)
else:
self.prevButton.setEnabled(True)
self.nextButton.setEnabled(True)
# 设置总数页文本
def setTotalPageLabel(self):
szPageCountText = ("总共%d页" % self.totalPage)
self.totalPageLabel.setText(szPageCountText)
# 设置总记录数
def setTotalRecordLabel(self):
szTotalRecordText = ("共%d条" % self.totalRecrodCount)
print('*** setTotalRecordLabel szTotalRecordText=' + szTotalRecordText)
self.totalRecordLabel.setText(szTotalRecordText)
# 前一页按钮按下
def onPrevButtonClick(self):
print('*** onPrevButtonClick ');
limitIndex = (self.currentPage - 2) * self.PageRecordCount
self.recordQuery(limitIndex)
self.currentPage -= 1
self.updateStatus()
# 后一页按钮按下
def onNextButtonClick(self):
print('*** onNextButtonClick ');
limitIndex = self.currentPage * self.PageRecordCount
self.recordQuery(limitIndex)
self.currentPage += 1
self.updateStatus()
# 转到页按钮按下
def onSwitchPageButtonClick(self):
# 得到输入字符串
szText = self.switchPageLineEdit.text()
print(szText)
# 数字正则表达式
pattern = re.compile(r'^[-+]?[0-9]+\.[0-9]+$')
match = pattern.match(szText)
# print(match)
# # 判断是否为数字
# 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.recordQuery(limitIndex);
# 设置当前页
self.currentPage = pageIndex
# 刷新状态
self.updateStatus();
if __name__ == '__main__':
from pyqt5_plugins.examples.exampleqmlitem import QtCore
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv)
if createTableAndInit():
# 创建窗口
example = DataGrid()
# 显示窗口
example.show()
sys.exit(app.exec_())