警告

本节包含从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)

QSqlTableModelQSqlQuery 的一个高级替代方案,用于导航和修改单个 SQL 表。它通常会导致代码量减少,并且不需要了解 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 是一个外键。

foreignkeys2

foreignkeys2

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

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

model.setTable("employee")

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

详情请参阅QSqlRelationalTableModel文档。