一、SQL与数据库
数据库 (database)是统一管理的、有组织的、可共享的大量数据的集合。数据库将数据存储在一个或多个表格中,管理这个数据库的软件称为 数据库管理系统(database management system, DBMS)。
数据库不是针对具体的应用程序,而是立足于数据本身的管理,它将所有数据保存在数据库中,进行科学的组织,并借助于数据库管理系统,通过 SQL 与各种应用程序或应用系统连接,使之能方便地使用数据库中的数据。
关系型数据库管理系统一般都支持结构化查询语言 (structured query language, SQL),SQL 是数据库的基础,通过它可以实现对关系型数据库进行查询、新增、更新、删除、求和和排序等操作。关系型数据库由数据表 (table)构成,数据表的一行数据称为字段,可以在数据库中添加和删除数据表,在数据表中可以查询、添加和删除字段。
SQL 语句主要分为以下几类:
- 数据定义语言(data definition language, DDL)。DDL 是 SQL 中定义数据结构和数据库对象的语言,主要关键字有CREATE、ALTER 和 DROP。
- 数据操纵语言(data manipulation language, DML)。DML 是 SQL 中操纵数据库中数据的语言,可对数据库中的数据进行插入、删除、更新和选择,主要关键字有 INSERT、UPDATE、DELETE 和 SELECT。
- 事务控制语言(transaction control language, TCL)。TCL 用于管理 DML 对数据所作的修改,主要关键字有提交 COMMIT 和撤销 ROLLBACK。
- 对数据库的操作需要用 COMMIT 进行确认,事务一经提交就不能撤销,如果要在提交前撤销对数据库的操作,可以用 ROLLBACK 来 “回滚” 到相应事务开始时的状态。
- 数据控制语言(data control language, DCL)。DCL 是对数据访问权限进行控制、定义安全级别及创建用户的语言,主要关键字有 GRANT 和 REVOKE。
二、SQLite数据库
SQLite 数据库是一个常用的开源、跨平台、轻量化本机版数据库,可以作为嵌入式数据库使用。Python 自带的 sqlite3 可以实现对 SQLite 数据库的查询,使用前需要用 import sqlite3
语句导入 sqlite3。
sqlite3 提供了两个基本的类:数据库连接 Connection 和游标 Cursor。用 sqlite3 的 connect(database:str)
方法打开一个已经存在的 SQLite 数据库或新建一个数据库,并返回 Connection 对象,其中 databaseName是本机上已经存储的数据库文件,或者新建立的数据库文件名称,还可取 ":memory:",表示在内存中创建临时数据库。用 Connection 对象的 cursor()
方法获取 Cursor 对象,用 Cursor 对象提供的方法可以执行 SQL 指令。
数据库连接 Connection 类的常用方法如下:
cursor() -> Cursor # 创建并返回Cursor对象
commit() -> None # 提交当前的事务
interrupt() -> None # 停止还未执行的任务
rollback() -> None # 放弃对数据库的操作,返回到调用commit()时的状态
close() -> None # 关闭数据库
backup(target:Connection) -> None # 将数据备份到另一个数据库中
游标 Cursor 用于执行 SQL 语句,它的常用方法如下:
execute(sql:sqk, parameters:Sequence=()) -> None # 执行一条SQL语句,parameters是SQL中的占位符的值
executemany(sql:str, parameters:Sequence) -> None # 重复执行SQL语句,parameters是SQL中的占位符的值
executescript(sql_script:str) -> None # 执行多条SQL语句fetchone() -> Tuple # 获取数据表中的下一行数据构成的元组或None
fetchmany(size:int=cursor.arraysize) -> List # 获取多行数据,构成的列表,参数size是要获取的行数
fetchall() -> List # 获取所有剩余的行构成的列表close() -> None # 关闭游标
import sqlite3connection = sqlite3.connect("test.db") # 获取连接
cursor = connection.cursor() # 获取游标# 执行SQL语句,创建表
cursor.execute("create table if not exists user(name varchar(20), age int)")# 向表中插入数据,新增用户信息
cursor.execute("insert into user(name,age) values('Sakura',10)")
cursor.execute("insert into user(name,age) values('Mikoto',14)")
cursor.execute("insert into user(name,age) values('Shana',15)")# 执行查询结果
cursor.execute("select * from user")
# 获取查询结果
result = cursor.fetchone() # 使用fetchone()获取一条记录
print(result,end="\n\n")result = cursor.fetchmany(2) # 使用fetchmany()获取多条记录
print(result,end="\n\n")result = cursor.fetchall() # 使用fetchall()获取全部查询结果
print(result,end="\n\n")# 修改用户信息
# 使用问号作为占位符代替具体的数值,然后使用一个元组来替代问号
# 使用占位符的方式可以避免SQL注入的风险
cursor.execute("update user set age = ? where name = ?",(12,"Sakura"))
cursor.execute("select * from user where name = ?",("Sakura",))
result = cursor.fetchall()
print(result,end="\n\n")# 删除用户数据
cursor.execute("delete from user where name = ?",("Shana",))
cursor.execute("select * from user")
result = cursor.fetchall()
print(result,end="\n\n")cursor.close() # 关闭游标
connection.close() # 关闭数据库
三、PySide6对数据库的操作
PySide6 提供了对常用数据库的驱动,可以从数据库中进行查询、读取、写入、修改、删除数据等操作,同时提供了可视化的控件和数据库数据模型,可以将数据从数据库读取到数据模型中,然后用 Model/View 结构在图形界面中对数据进行操作。
PySide6 可以驱动常用的关系型数据库,在对数据库进行操作之前需要用 QSqlDatabase 类建立对数据库的连接,然后再用 QSqlQuery 类执行 SQL 命令,实现对数据库的操作。
我们可以在终端中使用 pip 安装 pyside6 模块。
pip install pyside6
3.1、数据库连接
在对数据库进行操作之前,需要先建立对数据库的连接。数据库连接用 QSqlDatabase 类。
用 QSqlDatabase 创建实例的方法如下所示:
QSqlDatabase()
QSqlDatabase(type:str)
其中 type 是数据库的驱动类型,可取的值下所示。如果要建立自定义的驱动类型,可以创建 QSqlDriver 的子类。
"QDB2" # IBM DB2数据库
"QIBASE" # Borlad InterBase数据库
"QMYSQL" # MySQL数据库
"QODBC" # 支持ODBC接口的数据库
"QPSQL" # PostgreSQL数据库
"QSQLITE" # SQLite数据库
"QOCI" # Oracle数据库
QSqlDatabase 类的常用方法如下:
# 实例方法
connectionName() -> str # 获取连接的名称
driverName() -> str # 获取驱动类型的名称setDatabaseName(name:str) -> None # 设置连接的数据库名称
databaseName() -> str # 获取连接的数据库名称
setHostName(host:str) -> None # 设置连接的主机名称
hostName() -> str # 获取连接的主机名称
setPort(port:int) -> None # 设置连接的端口号
port() -> int # 获取连接的端口号
setUserName(username:str) -> None # 设置用户名
userName() -> str # 获取用户名
setPassword(password:str) -> None # 设置密码
password() -> str # 获取密码
setConnectOptions(options="") -> None # 设置连接选项
connectOptions() -> str # 获取连接参数open() -> bool # 打开数据库
open(user:str, password:str) -> bool # 打开数据库
isOpen() -> bool # 获取数据库是否打开
isOpenError() -> bool # 获取打开数据库是是否出错
isValid() -> bool # 获取连接是否有效
close() -> None # 关闭连接transaction() -> bool # 开启事务
commit() -> bool # 提交事务
rollback() -> bool # 回滚事务
lastError() -> QSqlError # 获取最后的错误信息
record(tablename:str) -> QSqlRecord # 获取含有字段名称的记录setNumericalPrecisionPolicy(precisionPolicy:QSql.NumericalPrecisionPolicy) -> None # 设置对数据库进行查询时默认的数值精度
tables(type:QSql.TableType=QSql.Tables) -> List[str] # 根据表格类型参数,获取数据库中的表格名称# 静态方法
drivers() -> List[str] # 获取系统支持的驱动类型
isDriverAvailable(name:str) -> bool # 获取是否支持某种类型的驱动# 添加数据库连接
addDatabase(driver:str, connectionName:str=QLatin1StringView(QSqlDatabase.defaultConnection)) -> QSqlDatabase# 根据连接名称获取数据库连接
database(connectionName:str=QLatin1StringView(QSqlDatabase.defaultConnection), open:bool=true) -> QSqlDatabaseremoveDatabase(connectionName:str) -> None # 删除数据库连接connectionNames() -> List[str] # 获取已经添加的连接名称# 如果connectionNames()返回值中有指定的连接,则返回True
contains(connectionName:str=QLatin1StringView(QSqlDatabase.defaultConnection)) -> bool
用静态方法 addDatabase(type:str,connectionName:str='qt_sql_default_connection')
添加某种驱动类型的连接,其中参数 type 是驱动类型。对同一个数据库可以添加多个连接,数据库连接的识别是通过连接名称 connectionName 来区分的,而不是关联的数据库。如果不输入连接名称,则该连接作为默认连接,将使用默认的连接名称 'qt_sql_default_connection'
。
在用 open()
方法打开数据库前,需要分别用 setDatabaseName(name:str)
方法、setHostName(host:str)
方法、setPassword(password:str)
方法、setPort(port:int)
方法、setUserName(name:str)
方法、setConnectOptions(options:str='')
方法设置连接的数据库文件名、主机名、密码、端口号、用户名和连接参数,如果用 open() 方法打开数据库后再设置这些参数将不起作用。
在用 setDatabaseName(name:str)
方法打开 SQLite 数据库时,如果数据库不存在则创建新数据库,参数 name 也可取 ':memory:'
,在内存中临时创建数据库,程序运行结束后删除数据库。对于 ODBC 数据库,参数 nam e是 *.dsn
文件或连接字符串;对于 Oracle 数据库,name 参数是 TNS服务名称
。
用 setConnectOptions(options:str='')
方法设置数据库的参数,不同的驱动类型需要设置的参数也不同,各参数值之间用分号 “;” 隔开,例如 SQLite 数据库,可选参数如下:
QSQLITE_BUSY_TIMEOUT
QSQLITE_OPEN_READONLY
QSQLITE_OPEN_URI
QSQLITE_ENABLE_SHARED_CACHE
QSQLITE_ENABLE_REGEXP
QSQLITE_NO_USE_EXTENDED_RESULT_CODES
用 tables(type:QSql.TableType=QSql.Tables)
方法获取数据库中存在的数据表名称列表,其中 type 取值是 QSql.TableType 的枚举值,可取值如下:
QSql.TableType.Tables # 对用户可见的所有表
QSql.TableType.SystemTables # 数据库使用的内部表
QSql.TableType.Views # 对用户可见的所有视图
QSql.TableType.AllTables # 以上三种表和视图
用 setNumericalPrecisionPolicy(precisionPolicy:QSql.NumericalPrecisionPolicy)
方法设置对数据库进行查询时默认的数值精度,参数 precisionPolicy 可取值如下:
QSql.NumericalPrecisionPolicy.LowPrecisionInt32 # 32位整数,忽略小数部分
QSql.NumericalPrecisionPolicy.LowPrecisionInt64 # 64位整数,忽略小数部分
QSql.NumericalPrecisionPolicy.LowPrecisionDouble # 双精度值,默认值
QSql.NumericalPrecisionPolicy.HighPrecision # 保持数据的原有精度
用 lastError()
方法获取最后的出错信息 QSqlError 对象,用 QSqlError 的 type()
方法可以获取出错类型,返回值是 QSqlError.ErrorType 的枚举值或 -1(不能确定错误类型),QSqlError.ErrorType 的枚举值如下:
QSqlError.ErrorType.NoError # 0,没有错误
QSqlError.ErrorType.ConnectionError # 1,数据库连接错误
QSqlError.ErrorType.StatementError # 2,SQL命令语法错误
QSqlError.ErrorType.TransactionError # 3,事务错误
QSqlError.ErrorType.UnknownError # 4,未知错误
3.2、数据库查询
数据库查询 QSqlQuery 用于执行标准的 SQ L命令,例如 CREATE TABLE、SELECT、INSERT、UPDATE、DELETE 等,还可执行特定的非标准的 SQL 命令。
用 QSqlQuery 类创建实例对象的方法如下所示:
QSqlQuery(db:QSqlDatabase)
QSqlQuery(other:QSqlQuery)
QSqlQuery(query:str="", db:QSqlDatabase=Default(QSqldatabase))
QSqlQuery 类常用方法如下:
prepare(query:str) -> bool # 准备SQL语句,成功返回TrueaddBindValue(val:Any, type:QSql.ParamType=QSql.In) -> None # 如果prepare(query)中有占位符,则按顺序依次设置占位符的值
bindValue(placeholder:str, val:Any, type:QSql.ParamType=QSql.In) -> None # 如果prepare(query)中有占位符,则根据占位名称设置占位符的值
bindValue(pos:int, val:Any, type:QSql.ParamType=QSql.In) -> None # 如果prepare(query)中有占位符,则根据占位位置设置占位符的值boundValue(placeholder:str) -> Any # 根据占位符名称获取绑定值
boundValue(pos:int) -> Any # 根据占位位置获取绑定值
boundValues() -> List[Any] # 获取绑定值列表exec() -> bool # 执行prepare(query)准备的SQL语句
exec(query:str) -> bool # 执行SQL语句,成功返回True
# 批处理用prepare()方法准备的命令
execBatch(mode:QSqlQuery.BatchExecutionMode=QSqlQuery.BatchExecutionMode.ValuesAsRows) -> boolfinish() -> None # 完成查询,不再获取数据
clear() -> None # 清空结果,释放所有资源,查询处于不活跃状态executedQuery() -> str # 返回最后正确执行的SQL语句
lastQuery() -> str # 返回当前查询使用使用的SQL语句# 返回查询的当前内部位置,第一个记录位置是0,如果位置无效,则返回值是QSql.BeforeFirstRow(值是-1)或QSql.AfterLastRow(值是-2)
at() -> intisSelect() -> bool # 当前SQL语句是SELECT语句时返回True
isValid() -> bool # 当前查询定位在有效记录时返回True
isActive() -> bool # 获取查询是否处于活跃状态
isNull(field:int) -> bool # 将查询处于非活跃状态,查询定位在无效记录或空字段上时返回True
isNull(name:str) -> bool # 将查询处于非活跃状态,查询定位在无效记录或空字段上时返回Truefirst() -> bool # 将当前查询位置定位在第一个记录
last() -> bool # 将当前查询位置定位到最后一个记录
previous() -> bool # 将当前查询位置定位到前一个记录
next() -> bool # 将当前查询位置定位到下一个记录
seek(i:int, relative:bool=false) -> bool # 将当前查询位置定位到指定记录setForwardOnly(forward:bool) -> None # 当forward取True时,只能用next()和seek()方法来定位结果,此时,seek()参数为正值
isForwardOnly() -> bool # 获取定位模式lastError() -> QSqlError # 返回最近出错信息
lastInsertId() -> Any # 返回最近插入行的对象ID号
nextResult() -> bool # 放弃当前查询结果并定位到下一个结果
record() -> QSqlRecord # 返回查询指向的当前记录size() -> int # 返回查询结果的记录数,无法确定、非SELECT命令或数据库不支持该功能是返回-1、
value(i:int) -> Any # 根据字段索引,获取当前记录的字段值
value(name:int) -> Any # 根据字段名称,获取当前记录的字段值numRowsAffected() -> int # 获取受影响的行的个数,无法确定或查询处于非活跃状态时返回-1
swap(other:QSqlQuery) -> None # 与其它查询交换数据
用 exec(query:str)
方法直接执行 SQL 命令。也可以用 prepare(query:str)
方法准备要执行的 SQL 命令;用 exec()
方法或 execBatch(mode=QSqlQuery.ValuesAsRows)
方法执行已经准备好的 SQL 命令,其中 mode 可取值如下:
QSqlQuery.BatchExecutionMode.ValuesAsRows # 更新多行,列表中的每个值作为一个值来更新下一行
QSqlQuery.BatchExecutionMode.ValuesAsColumns # 更新一行,列表作为一个值来使用
在用 prepare(query:str)
方法准备 SQL 命令时,SQL 命令中可以有占位符,占位符可以用问号 "?"
(ODBC 格式),也可以用冒号 ":surname"
(Oracle 格式)。占位符的真实值可以用 addBindValue(val:Any,type:QSql.ParamType=QSql.In)
方法按照 顺序 依次设置,也可用 bindValue(placeholder:str,val:Any,type:QSql.ParamType=QSql.In)
方法根据 占位符的名称 设置,还可以用 bindValue(pos:int,val:Any,type:QSql.ParamType=QSql.In)
方法根据 占位符的位置 设置,其中参数 type可取值如下:
QSql.ParamTypeFlag.In # 绑定参数输入到数据库中
QSql.ParamTypeFlag.Out # 绑定参数从数据库中接收数据
QSql.ParamTypeFlag.InOut # 既可以将数据输入到数据库中,也可以从数据库中接收数据
QSql.ParamTypeFlag.Binary # 数据是二进制,需要将“|”与以上三种参数联合使用
当返回的结果有多个记录时,需要首先定位到所需要的记录上,当 isActive()
方法和 isSelect()
方法的返回值是 True 时,可以用 first()
、last()
、previous()
和 next()
方法分别定位到 第一个记录、最后一个记录、前一个记录 和 下一个记录 上,成功则返回 True;用 seek(index:int,relative:bool=False)
方法可以 定位到指定的记录 上。如果只是想从开始到结束浏览数据,可以设置 setForwardOnly(True)
,这样可以节省大量的内存。
用 value(index:int)
方法或 value(name:str)
方法获取当前记录的字段值。也可用 record()
方法获取当前的记录对象 QSqlRecord,QSqlRecord 是指数据表(table)或视图(view)中的一行,然后用记录对象的 value(index:int)
方法或 value(name:str)
方法获取字段的值,用记录对象的 count()
方法获取字段的数量,用 indexOf(name:str)
方法获取字段的索引。
from PySide6.QtSql import QSqlDatabase, QSqlQueryif __name__ == "__main__":person = (("Sakura", 10), ("Mikoto", 14), ("Shana", 15))# 1.添加数据库连接db = QSqlDatabase.addDatabase("QSQLITE")# 2.设置连接数据库的名称db_name = "./test.db"db.setDatabaseName(db_name)# 3.创建数据库查询对象query = QSqlQuery(db)# 3.打开数据库if db.open():# 4.执行SQL语句,创建表query.exec("create table if not exists user(name varchar(20), age int)")# 6.开启事务if db.transaction():for i in person:# 7.准备SQL语句query.prepare("insert into user(name, age) values(?, ?)")# 7.1.按顺序设置占位符的值query.addBindValue(i[0])# 7.2.按索引位置设置占位符的值query.bindValue(1, i[1])# 8.执行SQL语句query.exec()# 9.提交事务db.commit()# 10.查询数据if query.exec("select * from user"):while query.next():print(query.value("name"), query.value("age"))# 11.关闭数据库db.close()
四、数据库Model/View结构
PySide6 提供了对数据库进行可视化操作的 Model/View 结构,通过数据库模型读入在数据库中查询到的数据,并通过视图控件(如 QTableView)显示数据库模型中的数据,通过代理控件在视图控件中对数据进行新增、更新、删除等操作,再通过数据模型把操作后的数据保存到数据库中。PySide6 提供的数据库模型有 QSqlQueryModel、QSqlTableModel 和 QSqlRelationalTableModel。
4.1、数据库查询模型
数据库查询模型 QSqlQueryModel 只能从数据库中读取数据,而不能修改数据,可以用视图控件。
用 QSqlQueryModel 创建数据库查询模型对象的方法如下所示。
QSqlQueryModel(paarent:QObject=None)
QSqlQueryModel 类常用方法如下:
setQuery(query:QSqlQuery) -> None # 设置数据库查询
setQuery(query:str, db:QSqkDatabase=QSqlDatabase()) -> None # 设置数据库查询
query() -> QSqlQuery # 获取数据库查询
record() -> QSqlRecord # 获取包含字段信息的空记录
record(row:int) -> QSqlRecord # 获取指定行的记录
clear() -> None # 清空查询模型中的数据# 设置显示数据的视图控件表头某角色的值
setHeaderData(section:int, orientation:Qt.Orientation, value:Any, role:int=Qt.EditRole) -> bool
# 获取显示数据的视图控件表头某种角色的值
headerData(section:int, orientation:Qt.Orientation, role:int=Qt.DisplayRole) -> AnyrowCount(parent:QModelIndex=QModelIndex()) -> int # 获取数据表中记录(行的数量)
columnCount(parent:QModelIndex=QModelIndex()) -> int # 获取数据表中列的数量
用 setQuery(query:QSqlQuery)
方法或 setQuery(query:str,db:QSqlDatabase=Default(QSqlDatabase))
方法设置数据库查询 QSqlQuery;用 setHeaderData(section:int,orientation:Qt.Orientation,value:Any,role:int=Qt.EditRole)
方法设置显示数据的视图控件表头某角色的值,在 orientation 取 Qt.Horizontal,并且 section 取值合适时返回 True,其他情况返回 False,其中 value 是某种角色的值,section 是列索引。
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QTableView
from PySide6.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
from PySide6.QtCore import Qtclass MyWidget(QWidget):def __init__(self):# 1.调用父类Qwidget类的__init__()方法super().__init__()# 2.使用数据库self.useDataBase()# 3.调用setupUi()方法初始化页面self.setup_ui()def setup_ui(self):# 1.设置窗口对象大小self.resize(700, 500)# 2.设置表格控件self.tableView = QTableView(self)self.tableView.resize(700, 500)# 3.设置表格控件的模型self.tableView.setModel(self.sqlQueryModel)def useDataBase(self):person = (("Sakura", 10), ("Mikoto", 14), ("Shana", 15))# 1.添加数据库连接db = QSqlDatabase.addDatabase("QSQLITE")# 2.设置连接数据库的名称db_name = "./test.db"db.setDatabaseName(db_name)# 3.创建数据库查询对象query = QSqlQuery(db)# 4.创建数据库查询模型self.sqlQueryModel = QSqlQueryModel()# 5.打开数据库if db.open():# 6.执行SQL语句,创建表self.sqlQueryModel.setQuery("create table if not exists user(name varchar(20), age int)")# 7.开启事务if db.transaction():for i in person:# 8.准备SQL语句query.prepare("insert into user(name, age) values(?, ?)")# 8.1.按顺序设置占位符的值query.addBindValue(i[0])# 8.2.按索引位置设置占位符的值query.bindValue(1, i[1])# 9.执行SQL语句query.exec()# 10.提交事务db.commit()# 11.设置查询self.sqlQueryModel.setQuery("select * from user")# 12.获取字段信息当作头部信息header = self.sqlQueryModel.record()for i in range(header.count()):# 13.设置显示数据的视图控件表头某角色的值self.sqlQueryModel.setHeaderData(i, Qt.Orientation.Horizontal, header.fieldName(i), Qt.ItemDataRole.DisplayRole)# 14.关闭数据库db.close()if __name__ == "__main__":# 1.创建一个QApplication类的实例app = QApplication(sys.argv)# 2.创建一个窗口window = MyWidget()# 3.展示窗口window.show()# 4.进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
4.2、数据库表格模型
数据库表格模型 QSqlTableModel 借助视图控件可以对查询到的数据进行修改、插入、删除和排序等操作,同时将修改后的数据更新到数据库中。
用 QSqlTableModel 创建数据库表格模型的方法如下所示:
QSqlTableModel(parent:QObject=None, db:QSqlDatabase=Default(QSqlDataBase))
数据库表格模型 QSqlTableModel 的常用犯法按如下所示:
# 实例方法
insertRows(row:int, count:int, parent:QModelIndex=QModelIndex()) -> bool # 插入多个空行,在OnFieldChange和OnRowChange模式下每次只能插入一行
removeRow(row:int, parent:QModelIndex=QModelIndex()) -> bool # 删除指定行
removeRows(row:int, count:int, parent:QModelIndex=QModelIndex()) -> bool # 删除多行
insertColumns(column:int, count:int, parent:QModelIndex=QModelIndex()) -> bool # 插入多个空列
removeColumn(column:int, parent:QModelIndex=QModelIndex()) -> bool # 删除指定列
removeColumns(column:int, count:int, parent:QModelIndex=QModelIndex()) -> bool # 删除多列
revert() -> None # 恢复数据模型到初始状态
submit() -> bool # 提交数据模型中的所有更改
rowCount(parent:QModelIndex=QModelIndex()) -> int # 获取行的数量
columnCount(parent:QModelIndex=QModelIndex()) -> int # 获取列的数量
setData(index:QModelIndex, value:Any, role:Qt.ItemDataRole=Qt.EditRole) -> bool # 设置指定索引的数据项的角色值
data(index:QModelIndex, role:Qt.ItemDataRole=Qt.EditRole) -> Any # 获取指定索引的数据项的角色值
sort(column:int, order:Qt.SortOrder=Qt.AscendingOrder) -> None # 直接对结果进行排序
index(row:int, column:int, parent:QModelIndex=QModelIndex()) -> QModelIndex # 获取子索引
parent(child:QModelIndex)-> QModelIndex # 获取子索引的父索引
sibling(row:int, column:int, idx:QModelIndex) -> QModelIndex # 获取指定索引的兄弟索引
clearItemData(index:QModelIndex) -> bool # 根据索引清除数据项中的数据setEditStrategy(strategy:QSqlTableModel.EditStrategy) -> None # 设置修改提交模式
database() -> QSqlDatabase # 获取关联的数据库连接
deleteRowFromTable(row:int) -> bool # 直接删除数据表中指定的行(记录)
fieldIndex(fieldName:str) -> int # 获取字段的索引,-1表示没有对应的字段
insertRecord(row:int, record:QSqlRecord) -> bool # 在指定行位置插入行
insertRowIntoTable(values:QSqlDatabase) -> bool # 直接在数据表中插入行isDirty() -> bool # 获取模型中是否有脏数据
isDirty(index:QModelIndex) -> bool # 根据索引获取数据数据是否时脏数据
primaryValues(row:int) -> QSqlRecord # 返回指定行的含有表格字段的记录
revertRow(row:int) -> None # 复原指定行的更改setRecord(row:int, record:QSqlRecord) -> bool # 用指定的记录填充指定的行
setTable(tableName:str) -> None # 设置数据表中的字段名称
setFilter(filter:str) -> None # 设置SELECT查询语句中WHERE子句部分
filter() -> str # 获取SELECT查询语句中WHERE子句部分
setSort(column:int, order:Qt.SortOrder) -> None # 设置SELECT查询语句中ORDER BY子句部分
orderByClause() -> str # 获取SELECT查询语句中ORDER BY子句部分select() -> bool # 执行SELECT查询语句
selectRow(row:int) -> bool # 用数据库库中行更新模型中的数据
selectStatement() -> bool # 获取"SELECT ... WHERE ... ORDER BY..."# 槽函数
revertAll() -> None # 复原所有未提交的更改
submitAll() -> bool # 提交所有更改
数据库表格模型 QSqlTableModel 的常用犯法按如下所示:
beforeDelete(row:int) # 在调用deleteRowFromTable(row:int)方法删除指定行之前发色和信号
beforeInsert(record:QSqlRecord) # 在调用insertRowIntoTable(values:QSqlRecord)方法插入记录之前发射信号,可以在插入之前修改记录
beforeUpdate(row:int, record:QSqlRecord) # 在调用updateRowInTable(row:int, values:QSqlRecord)方法更新指定行之前发射信号
primeInsert(row:int, record:QSqlRecord) # 在调用insertRows(row:int, column:int)方法对新插入的行进行初始化时发射信号
记录 QSqlRecord 表示数据表中的一行数据,一行数据中每个字段有不同的值,可用 QSqlTableModel 的 record(row:int)
方法获取 QSqlRecord 对象,以获取数据表中的一行数据。
用 QSqlRecord 创建记录实例对象的方法如下所示。
QSqlRecord()
QSqlRecord(other:QSqlRecord)
QSqlRecord 常用的方法如下所示。
append(field:QSqlField) -> None # 在末尾添加字段
insert(pos:int, field:QSqlField) -> None # 在自会顶的位置插入字段
remove(pos:int) -> None # 删除指定位置的字段
replace(pos:int, field:QSqlField) -> None # 替换指定位置的字段
setValue(name:str, val:Any) -> None # 根据字段名称设置字段的值
setValue(i:int, val:Any) -> None # 根据字段索引设置字段的值
value(name:str) -> Any # 根据字段名称获取字段的值
value(i:int) -> Any # 根据字段索引获取字段的值
setNull(name:str) -> None # 根据字段名称设置字段为NULL
setNull(i:int) -> None # 根据字段索引设置字段为NULL
isNull(name:str) -> bool # 根据字段名称判断字段是否为NULL
isNull(i:int) -> bool # 根据字段索引判断字段是否为NULL
clear() -> None # 删除所有的字段
isEmpty() -> bool # 获取是否含有字段
clearValues() -> None # 删除所有的字段值
contains(name:str) -> bool # 获取是否包含指定的字段
count() -> int # 获取字段的数量
field(name:str) -> QSqlField # 根据字段名称获取字段
field(i:int) -> QSqlField # 根据字段索引获取字段
fieldName(i:int) -> str # 获取字段的名称
indexOf(name:str) -> int # 获取字段的索引
keyValues(keyFields:QSqlRecord) -> QSqlRecord # 获取与给定的记录具有相同字段名称的记录
setGenerated(name:str, generated:bool) -> None # 根据索引设置字段值是否已经生成
setGenerated(i:int, generated:bool) -> None # 根据索引设置字段值是否已经生成
isGenerated(name:str) -> bool # 根据索引获取字段是否已经生成
isGenerated(i:int) -> bool # 根据名称获取字段是否已经生成
用 append(field:QSqlField)
方法可以在末尾添加字段;用 insert(pos:int,field:QSqlField)
方法插入字段;用 remove(pos:int)
方法移除字段;用 setValue(i:int,val:Any)
方法或 setValue(name:str,val:Any)
方法根据字段索引或字段名称设置字段的值;用 setGenerated(i:int,generated:bool)
方法或 setGenerated(name:str,generated:bool)
方法根据索引或名称设置字段值是否已经生成,只有已经生成的字段值才能用 QSqlTableModel 的 updateRowInTable(row:int,values:QSqlRecord)
方法更新到数据库中,默认值是 True。
字段 QSqlField 是数据表中的列,一个记录由多个字段构成。字段的属性有字段名、字段类型和字段值等。用 QSqlRecord 的 field(i:int)
方法或 field(name:str)
方法可获得 QSqlField。
用 QSqlField 创建字段的方法如下所示。
QSqlField(fieldName:str="", type:QMetaType:Default(QMetaType), tableName:str="")
QSqlField(other:QSqlField)
其中 type 用于定义字段的类型,可取 PySide 中常见的类。
QSqlField 类的常用方法如下:
setName(name:str) -> None # 设置字段的名称
name() -> str # 获取字段的名称
setValue(value:Any) -> None # 获取字段的值,只读时不能设置值
value() -> Any # 获取字段的值,只读时不能设置值
setDefaultValue(value:Any) -> None # 设置字段的默认值
defaultValue() -> Any # 获取字段的默认值
setMetaType(type:QMetaType) -> None # 设置字段的类型
metaType() -> QMetaType # 获取存储在数据库中的类型
setReadOnly(readOnly:bool) -> None # 设置是否只读,只读时不能修改字段的值
isReadOnly() -> bool # 获取是否只读
setRequired(required:bool) -> None # 设置字段的值是必须要输入还是可见的
setRequiredStatus(status:QSqlFieldRequiredStatus) -> None # 设置可选状态
setGenerated(gen:bool) -> None # 设置字段的生成状态
isGenerated() -> bool # 获取字段的生成状态
setLength(fieldLength:int) -> None # 设置字段的长度
length() -> int # 获取字段的长度
setPrecision(precision:int) -> None # 设置浮点数的精度
precision() -> int # 获取浮点数的精度
setTableName(tableName:str) -> None # 设置数据表名称
tableName() -> str # 获取数据表名称
setAutoValue(autoVal:bool) -> None # 将字段的值标记是由数据库自动生成的
isAutoValue() -> bool # 获取字段的值是否是由数据库自动生成的
isValid() -> bool # 获取字段的类型是否有效
clear() -> None # 清除字段的值并设置成None
isNull() -> bool # 获取字段的值是否为None
用 setName(name:str)
方法设置字段名称;用 setValue(value:Any)
方法设置字段的值;用 setDefaultValue(value:Any)
方法设置字段的默认值;用 setReadOnly(readOnly:bool)
方法设置是否是只读,在只读状态不能更改字段的值。用 setRequired(required:bool)
方法或 setRequiredStatus(status:QSqlField.RequiredStatus)
方法设置字段的值是必须要输入的还是可选的,其中参数 status 可取值如下:
QSqlField.RequiredStatus.Required
QSqlField.RequiredStatus.Optional
QSqlField.RequiredStatus.Unknown
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QTableView
from PySide6.QtSql import QSqlDatabase, QSqlTableModel, QSqlRecordclass MyWidget(QWidget):def __init__(self):# 1.调用父类Qwidget类的__init__()方法super().__init__()# 2.使用数据库self.useDataBase()# 3.调用setupUi()方法初始化页面self.setup_ui()def setup_ui(self):# 1.设置窗口对象大小self.resize(700, 500)# 2.设置表格控件self.tableView = QTableView(self)self.tableView.resize(700, 500)# 3.设置表格控件的模型self.tableView.setModel(self.sqlTableModel)def useDataBase(self):persons = [{"name": "Sakura", "age": 10}, {"name": "Mikoto", "age": 14}, {"name": "Shana", "age": 10}]# 1.添加数据库连接db = QSqlDatabase.addDatabase("QSQLITE")# 2.设置连接数据库的名称db_name = "./test.db"db.setDatabaseName(db_name)# 3.创建数据库表格模型self.sqlTableModel = QSqlTableModel(self, db)# 4.打开数据库if db.open():# 5.执行SQL语句,创建表self.sqlTableModel.setQuery("create table if not exists user(name varchar(20), age int)")# 6.设置数据表中字段的名称self.sqlTableModel.setTable("user")# 7.开启事务if db.transaction():for i, person in enumerate(persons):# 8.创建QSqlRecord对象,表示数据表中的一行数据record = QSqlRecord(self.sqlTableModel.record())for key, value in person.items():# 9.根据字段名称设置字段的值record.setValue(key, value)# 10.在指定位置插入行self.sqlTableModel.insertRecord(i, record)# 11.提交事务db.commit()# 12.查询数据self.sqlTableModel.select()# 13.关闭数据库db.close()if __name__ == "__main__":# 1.创建一个QApplication类的实例app = QApplication(sys.argv)# 2.创建一个窗口window = MyWidget()# 3.展示窗口window.show()# 4.进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
4.3、关系表格模型
数据库关系表格模型 QSqlRelationalTableModel 继承自 QSqlTableModel,除具有 QSqlTableModel 的方法外,它还提供了外键功能。关系表格模型 QSqlRelationalTableModel 实现了 SQL 的 SELECT 命令中的 INNER JOIN 和 LEFT JOIN 功能。
用 QSqlRelationalTableModel 类创建关系表格模型的方法如下所示。
QSqlRelationalTableModel(parent:QObject=None, db:QSqlDatabase=Default(QSqlDatabase))
用 QSqlRelationalTableModel 的 setRelation(column:int,relation:QSqlRelation)
方法定义 QSqlRelationalTableModel 当前数据表格(如 table1)的外键和映射关系,其中参数 column 是 table1 的字段编号,用于确定 table1 中当作外键的字段 field1,relation 参数是 QSqlRelation 的实例对象,用于确定另外一个数据表格(如 table2)和对应的字段 field2。
QSqlRelation 实例对象的创建方法是 QSqlRelation(tableName:str,indexCol:str,displayCol:str)
,其中 tableName 用于确定第 2 个数据表格 table2,indexCol 用于指定 table2 的字段 field2,displayCol 是 table2 中用于显示在 table1 的 field1 位置处的字段 field3,用 field3 的值显示在 field1 位置处,field1 的值不显示。
另外用 QSqlRelationalTableModel 的 setJoinMode(joinMode:QSqlRelationalTableModel.JoinMode)
方法可设置两个数据表格的数据映射模式,即使 table1 和 table2 没有匹配的数据,也列出 table1 中的数据。参数 joinMode 可取值如下:
QSqlRelationalTableModel.InnerJoin # 内连接,值为0,只列出table1和table2中匹配的数据
QSqlRelationalTableModel.LeftJoin # 左连接,值为1