【发布时间】:2022-01-24 02:03:19
【问题描述】:
前提:这个问题可能指的是两个不同的问题,但我相信它们可能是有联系的。如果在 cmets 和进一步研究之后我们会发现它们实际上是不相关的,我将打开一个单独的问题。
我在 QSqlTableModel 的某些方面遇到了一些意外和奇怪的行为,并且至少在一种情况下使用子类化。我不是 Sql 专家,但其中一个问题似乎不是预期的行为。
我只能为 SQLite 确认这一点,因为我不使用其他数据库系统。
我还可以使用 [Py]Qt 5.15.2 和 6.2.2 重现这些问题。
1。忽略编辑器更改后,新行被“删除”
使用默认的OnRowChange编辑策略,如果添加一行,则在字段中插入一些数据,使用Escanother字段的编辑/kbd>,然后从视图中删除 整个行。
不过,实际的数据库仍在更新,再次打开程序会显示之前“隐藏”的行,但已取消的字段除外。
from PyQt5 import QtWidgets, QtSql
class TestModel(QtSql.QSqlTableModel):
def __init__(self):
super().__init__()
QtSql.QSqlQuery().exec(
'CREATE TABLE IF NOT EXISTS test (name, value, data);')
self.setTable('test')
self.select()
app = QtWidgets.QApplication([])
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('test.db')
db.open()
win = QtWidgets.QWidget()
layout = QtWidgets.QVBoxLayout(win)
addButton = QtWidgets.QPushButton('Add row')
layout.addWidget(addButton)
table = QtWidgets.QTableView()
layout.addWidget(table)
model = TestModel()
table.setModel(model)
addButton.clicked.connect(lambda: model.insertRow(model.rowCount()))
app.aboutToQuit.connect(model.submitAll)
win.resize(640, 480)
win.show()
app.exec()
这些是重现问题的步骤:
- 用按钮添加一行;
- 编辑至少一个字段,但不是所有字段;
- 开始编辑空白字段;
- 按 Esc;
- 关闭并重新启动程序;
在第 4 步之后,您会看到添加的行已从视图中删除,这并不完全出乎意料:由于策略是 OnRowChange,因此取消会还原所有缓存的更改(包括 insertRow());我不完全同意这种行为(想象一下填写几十个字段然后错误地按 Esc),但这不是重点。
出乎意料的是,模型实际上已经更新了新的行和在点击Esc之前已经提交的所有字段,并且重新启动程序会显示这一点。
2。实现data() 将不完整的记录恢复到以前的数据
编辑其行中包含空 (NULL) 字段的索引会带来不同的结果,无论 data() 是否已在子类中实现,即使覆盖只是调用基本实现 .
将以下内容添加到上面的TestModel 类中:
def data(self, index, role=QtCore.Qt.DisplayRole):
return super().data(index, role)
还有app.exec()之前的提交按钮:
submitButton = QtWidgets.QPushButton('Submit')
layout.addWidget(submitButton)
submitButton.clicked.connect(model.submitAll)
要重现问题,请按以下步骤操作:
- 打开一个数据库,其中至少有一行底部有一个空字段,类似于上面所做的(注意:“空字段”是指一个从未被编辑过的项目);
- 编辑该行中的任何字段并按Enter;
使用OnRowChange 或OnFieldChange 策略,结果是整行无效:垂直标题显示“!” (无效记录的提示)和所有字段被清除,包括那些具有数据库先前值的字段。
当编辑策略设置为OnManualSubmit 时,调用submitAll() 将恢复为数据库的原始值,就像更改已恢复一样。
如果底部为空字段的行不是,则行为略有不同;执行上面的前两个步骤,然后:
- 按下提交按钮;
- 关闭并重新启动程序;
在这种情况下,在第 3 步之后视图似乎已经接受了更改,但重新启动程序显示没有应用任何修改。
根据编辑策略和情况,行为会发生变化。通常,如果一条具有空字段的记录后跟至少一条设置了所有字段的记录,则在取消对该字段的编辑时,视图和模型会按预期运行。
至少在一种情况下,甚至根本不可能编辑一个空字段(我不得不承认,我做了很多随机/速度测试,当我发现我无法编辑一个我不记得的字段时重现它的步骤)。
同样奇怪的是setData()和submitAll()都返回True,而没有明确的lastError()。尽管如此,显示的(和存储的)数据会恢复到以前的数据库内容。
我相信这两个问题都可能是由一个常见的错误引起的,但是,在向 Qt 错误报告系统提交一些东西之前,我想得到一些反馈,特别是来自那些在 SQL 和其他数据库驱动程序方面更有经验的人,在为了提供更好的报告(并最终知道这些问题是否实际上相关)。
【问题讨论】:
-
再次试验后,我发现行为发生了很大变化。这发生在我对我的 arch linux 系统进行了广泛更新之后,其中包括对 qt5 和 pyqt5 的一些升级(以及许多其他内容)。我现在可以重现您问题中提到的许多问题。作为记录,我之前使用的是 qt5-base 5.15.2+kde+r263-1,现在使用的是 qt5-base 5.15.2+kde+r268-1。由于这使我早期的大部分 cmets 都过时了,因此我已将其删除。
-
@ekhumoro 非常感谢你之前的 cmets(我读过,但我没有足够的时间或精力来回复你[抱歉] 我不想添加不必要的 cmets,直到我能够提供有效的响应)。从您的最后评论看来,行为并没有因为实际的 Qt 版本而改变,而是来自配置的“混合”,这让我更加困惑:AFAIK Qt 使用自己的驱动程序,但我一直认为那些是直接“捆绑”在发行版中,并且它们的开发与框架的其余部分一起集中。
-
明确一点:我说的是this patch collection,在LTS version of Qt5 became commercial only 之后变得必要。
-
好的,这可能解释了为什么我们并不总是看到完全相同的东西。明天我会尝试做更多的实验并确认我现在看到的行为。
-
@ekhumoro 非常感谢!顺便说一句,我并不着急,而且我知道这类问题并不容易处理:如果您正在度假,请花点时间享受您的圣日......并致以最良好的祝愿! :-)
标签: python sqlite qt pyqt qsqltablemodel