PyQt6中QSqlQueryModel/QSqlTableModel返回正确行数但内容空白及data方法递归错误问题排查
解决QSqlQueryModel重写data()时的空值与递归错误问题
先来说说你遇到的两个核心问题,以及对应的解决思路:
一、为什么data()返回值全为None,列表显示为空?
问题根源在你使用self.record(r)获取数据的方式上——QSqlQueryModel的record()方法内部是通过调用模型的data()来构建记录的。而你重写的data()只处理了DisplayRole和TooltipRole,其他角色(比如获取列原始数据的默认角色)都没有返回有效值,导致record().value()拿到的全是None。
举个具体场景:当你调用self.record(r).value("name")时,这个方法会尝试通过data()获取name列(对应查询结果的第1列)的值,但你的data()既没处理列的区分,也没返回父类的默认实现,自然拿不到有效数据。
解决办法是直接操作模型的底层QSqlQuery对象,绕开record()的递归依赖:
def data(self, index, role): # 直接访问底层查询对象,跳过record()的递归调用 query = self.query() if query.seek(index.row()): if role == Qt.ItemDataRole.DisplayRole: v = query.value("name") print(f"row {index.row()} displayrole = {v}") return v elif role == Qt.ItemDataRole.ToolTipRole: v = query.value("age") print(f"row {index.row()} tooltiprole = {v}") return v # 所有未自定义的角色,交给父类处理 return super().data(index, role)
这样直接从原始查询结果中取值,就不会依赖重写后的data()方法,能正确获取数据库里的真实数据。
二、最初的data()写法为什么会触发RecursionError?
同样和record()的内部逻辑有关:当你在重写的data()里调用self.record(r)时,record()会反过来调用data()来获取每一列的数据,而你的data()又会再次调用record(),由此形成无限递归循环,最终触发RecursionError。
再加上你最初的代码没有返回父类的data()实现,所有未处理的角色都没有返回值,进一步加剧了递归的触发条件。
额外注意事项
- 重写
data()时,一定要在最后返回super().data(index, role),让父类处理你不需要自定义的角色,避免模型内部逻辑异常。 - 如果是多列场景,记得加上
index.column()的判断,针对不同列做自定义处理;你的场景里ListView只显示一列,所以可以忽略,但多列场景必须考虑。 - 换成
QSqlTableModel时,解决思路完全一致:避免在重写的data()里调用依赖data()的方法,直接访问底层数据或调用父类实现。
修改后运行代码,你会发现ListView能正常显示名称,鼠标悬停也能看到年龄的tooltip提示了。
内容的提问来源于stack exchange,提问作者Iain
相关产品推荐
相关产品推荐

