You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 09:52:37