QSqlTableModel.insertRecord()未按指定行参数插入记录问题
问题
使用QSqlTableModel的insertRecord方法插入记录时,传入row=-1可正常将记录追加到表末尾,但传入其他行号时,记录不会插入到指定位置,示例代码如下:
import sys from PySide6.QtWidgets import (QApplication, QMainWindow, QTableView) from PySide6.QtSql import QSqlDatabase, QSqlTableModel, QSqlQuery class SQLTableModel(QSqlTableModel): def __init__(self, parent=None): super().__init__(parent) query = QSqlQuery() query.exec( "CREATE TABLE table1" "(id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, " "type TEXT)" ) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.db = QSqlDatabase.addDatabase("QSQLITE") self.db.setDatabaseName("SQLTableDatabase.sqlite") self.db.open() self.table_view = QTableView() self.model = SQLTableModel() self.table_view.setModel(self.model) self.model.setTable("table1") for i in range(4): record = self.model.record() record.setValue("type", str(i)) self.model.insertRecord(-1, record) record = self.model.record() record.setValue("type", "TEST") self.model.insertRecord(2, record) # 为何该记录未插入到第2行位置? self.model.select() self.setCentralWidget(self.table_view) app = QApplication(sys.argv) mainwindow = MainWindow() mainwindow.show() sys.exit(app.exec())
原因
QSqlTableModel是关系型数据库的直接映射模型,关系型数据库的表本身没有内置的固定行顺序概念,数据在存储层的排列由数据库内部管理,和插入时传入的row参数没有关系。insertRecord方法的row参数,只对模型内存里暂存的未提交行生效,一旦调用select()从数据库拉取全量数据,模型会按默认规则(通常是主键升序)排列返回结果,之前传入的非-1行号不会影响数据库的返回顺序,自然看不到插入到指定位置的效果。
解决方案
要实现记录插入到指定显示位置,有两种常用方案:
- 持久化排序方案:在表中新增专门的排序字段(比如命名为
sort_order,整数类型),插入记录到指定位置时,先将该位置及之后所有记录的sort_order值+1,再给新记录设置对应位置的sort_order值,之后给模型设置按该字段升序排序再调用select(),即可持久化保持指定排列顺序。 - 临时显示排序方案:如果不需要把排序规则持久化到数据库,可以使用
QSortFilterProxyModel作为代理层,在内存中调整行的显示顺序,不需要修改原有表结构。
以下是基于持久化排序方案修改后的可运行代码:
import sys from PySide6.QtCore import Qt from PySide6.QtWidgets import (QApplication, QMainWindow, QTableView) from PySide6.QtSql import QSqlDatabase, QSqlTableModel, QSqlQuery class SQLTableModel(QSqlTableModel): def __init__(self, parent=None): super().__init__(parent) query = QSqlQuery() # 新增sort_order字段存储排序值 query.exec( "CREATE TABLE IF NOT EXISTS table1" "(id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, " "type TEXT, sort_order INTEGER)" ) def insert_row_at_position(self, row, record): # 先将指定位置及之后的记录排序值后移 self.database().transaction() query = QSqlQuery() query.prepare("UPDATE table1 SET sort_order = sort_order + 1 WHERE sort_order >= ?") query.addBindValue(row) query.exec() # 给新记录设置对应排序值 record.setValue("sort_order", row) res = self.insertRecord(-1, record) self.database().commit() # 按排序字段刷新数据 self.setSort(self.fieldIndex("sort_order"), Qt.AscendingOrder) self.select() return res class MainWindow(QMainWindow): def __init__(self): super().__init__() self.db = QSqlDatabase.addDatabase("QSQLITE") self.db.setDatabaseName("SQLTableDatabase.sqlite") self.db.open() self.table_view = QTableView() self.model = SQLTableModel() self.table_view.setModel(self.model) self.model.setTable("table1") # 设置按sort_order字段升序排列 self.model.setSort(self.model.fieldIndex("sort_order"), Qt.AscendingOrder) self.model.select() # 初始化插入4条测试数据 for i in range(4): record = self.model.record() record.setValue("type", str(i)) record.setValue("sort_order", i) self.model.insertRecord(-1, record) self.model.select() # 在第2行位置插入TEST记录 record = self.model.record() record.setValue("type", "TEST") self.model.insert_row_at_position(2, record) self.setCentralWidget(self.table_view) app = QApplication(sys.argv) mainwindow = MainWindow() mainwindow.show() sys.exit(app.exec())
内容的提问来源于stack exchange,提问作者amateur3057
相关产品推荐
相关产品推荐

