如何使用PyQt5.QtSql显示SQLite关联表数据?
嘿,我之前也折腾过QSqlRelationalTableModel的关联查询,刚开始确实摸不着头脑,尤其是JoinMode的用法,给你分享一下我踩坑后总结的实现方法,亲测有效!
核心思路
QSqlRelationalTableModel本身就支持关联表的查询和数据展示,关键是要正确设置关联关系和连接模式,如果需要显示关联表的额外字段,还要手动指定查询列。
分步实现 + 代码示例
假设我们有两个关联表:
customers:存储客户信息(id, name, email)orders:存储订单信息(id, customer_id, order_date, total),其中customer_id是关联customers.id的外键
1. 初始化数据库与测试数据
先搞定数据库连接和测试数据,确保关联关系有效:
import sys from PyQt5.QtWidgets import QApplication, QTableView from PyQt5.QtSql import (QSqlDatabase, QSqlRelationalTableModel, QSqlRelation) from PyQt5.QtCore import Qt # 初始化SQLite数据库 db = QSqlDatabase.addDatabase("QSQLITE") db.setDatabaseName("test.db") if not db.open(): print("数据库打开失败!") sys.exit(1) # 开启外键约束(SQLite默认关闭) db.exec_("PRAGMA foreign_keys = ON") # 创建测试表 db.exec_(""" CREATE TABLE IF NOT EXISTS customers ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT NOT NULL UNIQUE ) """) db.exec_(""" CREATE TABLE IF NOT EXISTS orders ( id INTEGER PRIMARY KEY AUTOINCREMENT, customer_id INTEGER NOT NULL, order_date TEXT NOT NULL, total REAL NOT NULL, FOREIGN KEY (customer_id) REFERENCES customers(id) ) """) # 插入测试数据 db.exec_("INSERT INTO customers (name, email) VALUES ('Alice', 'alice@example.com')") db.exec_("INSERT INTO customers (name, email) VALUES ('Bob', 'bob@example.com')") db.exec_("INSERT INTO orders (customer_id, order_date, total) VALUES (1, '2024-05-01', 99.99)") db.exec_("INSERT INTO orders (customer_id, order_date, total) VALUES (2, '2024-05-02', 149.99)")
2. 配置QSqlRelationalTableModel
这一步是关键,我们要设置关联关系、连接模式,并指定要展示的字段:
app = QApplication(sys.argv) view = QTableView() # 初始化关联表模型 model = QSqlRelationalTableModel(db=db) model.setTable("orders") # 设置主表为orders # 1. 设置外键关联:把orders表的customer_id列(索引1,从0开始)映射到customers表的name字段 # 参数:主表列索引、关联表名、关联表主键、要显示的关联表字段 model.setRelation(1, QSqlRelation("customers", "id", "name")) # 2. 设置连接模式(JoinMode) # 可选两种模式: # - InnerJoin:只显示主表中存在对应关联数据的行(比如没有客户的订单会被过滤) # - LeftJoin:显示主表所有行,关联表无匹配数据时显示空值 model.setJoinMode(QSqlRelationalTableModel.InnerJoin) # 3. 指定要查询的字段(如果需要显示关联表的额外字段,比如客户邮箱) # 注意要加上表名前缀,避免字段名冲突 model.setSelect("orders.id, orders.order_date, customers.name, customers.email, orders.total") # 设置表头显示文本 model.setHeaderData(0, Qt.Horizontal, "订单ID") model.setHeaderData(1, Qt.Horizontal, "订单日期") model.setHeaderData(2, Qt.Horizontal, "客户姓名") model.setHeaderData(3, Qt.Horizontal, "客户邮箱") model.setHeaderData(4, Qt.Horizontal, "订单总额") # 加载数据 model.select() # 关联模型到表格视图 view.setModel(model) view.resizeColumnsToContents() # 自动调整列宽 view.show() sys.exit(app.exec_())
关键注意点
- 外键约束必须开启:SQLite默认关闭外键约束,一定要执行
PRAGMA foreign_keys = ON,否则关联查询可能出问题,删除关联数据时也不会触发约束。 - 列索引别搞错:
setRelation()的第一个参数是主表的列索引,从0开始计数,比如orders表的customer_id是第二列(索引1)。 - 编辑功能自动生效:QSqlRelationalTableModel支持编辑,当你修改客户姓名列时,模型会自动把对应的
customer_id更新到orders表,不用手动写SQL。 - JoinMode的选择:如果你的主表可能存在没有关联数据的行(比如未分配客户的订单),就用
LeftJoin;如果只需要显示有完整关联数据的行,用InnerJoin。
内容的提问来源于stack exchange,提问作者CodingCat
相关产品推荐
相关产品推荐

