警告

本节包含从 C++ 自动翻译到 Python 的代码片段,可能包含错误。

使用 SQL 模型类#

除了 QSqlQuery 之外,Qt 还提供了三个高级类来访问数据库。这些类是 QSqlQueryModelQSqlTableModelQSqlRelationalTableModel

QSqlQueryModel

基于任意 SQL 查询的只读模型。

QSqlTableModel

对单个表进行读写操作的模型。

QSqlRelationalTableModel

具有外键支持的 QSqlTableModel 子类。

这些类是从 QAbstractTableModel(它反过来又继承自 QAbstractItemModel)派生的,使得在 QListView 和 QTableView 等项目视图类中展示数据库中的数据变得简单。这将在 在表格视图中展示数据 部分中详细介绍。

使用这些类的另一个优点是,可以使代码更容易适应其他数据源。例如,如果您使用 QSqlTableModel 并随后决定使用 XML 文件而不是数据库来存储数据,这基本上只是用一个数据模型替换另一个数据模型的问题。

SQL 查询模型#

QSqlQueryModel 提供基于 SQL 查询的只读模型。

示例

model = QSqlQueryModel()
model.setQuery("SELECT * FROM employee")
for i in range(0, model.rowCount()):
    id = model.record(i).value("id").toInt()
    name = model.record(i).value("name").toString()
    print(id, name)

使用 setQuery() 设置查询后,您可以使用 record (int) 访问单个记录。您还可以使用 data() 以及从 QAbstractItemModel 继承的任何其他函数。

此外,还有一个重载后的setQuery() 函数,它接受一个QSqlQuery 对象,并在其结果集上进行操作。这使得您可以使用 QSqlQuery 的任何功能来设置查询(例如,预编译查询)。

SQL表格模型#

QSqlTableModel 提供一个读-写模型,它可以同时处理单个 SQL 表。

示例

model = QSqlTableModel()
model.setTable("employee")
model.setFilter("salary > 50000")
model.setSort(2, Qt.DescendingOrder)
model.select()
for i in range(0, model.rowCount()):
    name = model.record(i).value("name").toString()
    salary = model.record(i).value("salary").toInt()
    print(name, salary)

QSqlTableModel 是针对导航和修改单个 SQL 表的高层替代品,比 QSqlQuery 更简单,通常代码更少,且无需了解 SQL 语法。

使用 record() 来检索表中的一行,使用 setRecord() 来修改行。例如,以下代码将每位员工的薪水提高10%。

for i in range(0, model.rowCount()):
    record = model.record(i)
    salary = record.value("salary").toInt()
     = 1.1
    record.setValue("salary", salary)
    model.setRecord(i, record)

model.submitAll()

您也可以使用从 QAbstractItemModel 继承而来的 data()setData() 函数来访问数据。例如,以下是如何使用 setData() 更新记录的示例。

model.setData(model.index(row, column), 75000)
model.submitAll()

以下是插入行并填充内容的示例。

model.insertRows(row, 1)
model.setData(model.index(row, 0), 1013)
model.setData(model.index(row, 1), "Peter Gordon")
model.setData(model.index(row, 2), 68500)
model.submitAll()

以下是删除连续五行的方法。

model.removeRows(row, 5)
model.submitAll()

removeRows() 的第一个参数是要删除的第一行的索引。

修改完记录后,您应该始终调用 submitAll() 确保更改被写入数据库。

何时以及是否需要调用 submitAll() 取决于表的 edit strategy 。默认策略是 OnRowChange ,这意味着待处理的更改将在用户选择不同的行时应用到数据库。其他策略包括 OnManualSubmit(所有更改都在模型中缓存,直到您调用 submitAll())和 OnFieldChange(不缓存任何更改)。这些策略在将 QSqlTableModel 与视图一起使用时非常有用。

OnFieldChange 似乎保证您无需显式调用 submitAll()。然而,存在两个陷阱。

  • 如果没有缓存,性能可能会显著下降。

  • 如果您修改主键,在尝试为其填充内容时,可能会丢失记录。

SQL关系表模型#

QSqlRelationalTableModel 扩展了 QSqlTableModel,以便提供对外键的支持。外键是指一个表中的一个字段与另一个表的键字段的1对1映射。例如,如果有一个名为 book 的表包含一个名为 authorid 的字段,它引用作者表中的 id 字段,那么我们称 authorid 是一个外键。

noforeignkeys1

foreignkeys2

左侧的截图显示了一个普通的 QSqlTableModel 在 QTableView 中的样子。外键(citycountry)没有被解析成可读的值。右侧的截图显示了一个包含解析了外键为可读文本字符串的 QSqlRelationalTableModel

以下代码片段显示了如何设置 QSqlRelationalTableModel

model.setTable("employee")

model.setRelation(2, QSqlRelation("city", "id", "name"))
model.setRelation(3, QSqlRelation("country", "id", "name"))

有关详细信息,请参阅 QSqlRelationalTableModel 文档。