154-数据库操作和模型-QSQL模型-关系表格模型QSqlRelationalTableModel

关系表格模型QSqlRelationalTableModel

QSqlRelationalTableModel类为单个数据库表提供了一个可编辑的数据模型,并支持外键。

数据库关系表格模型 QSqlRelationalTableModel 继承自QSqlTableModel,除具有QSqlTableModel 的方法外,它还提供了外键功能。

关系表格模型 QSqlRelationalTableModel 实现了SQL的 SELECT 命令中的 INNER JOIN LEFT JOIN 能。SELECT 命令中INNERJOIN和LEFTJOIN的格式如下。

SELECT * FROM table1 INNER JOIN table2 ON tablel.fleld1 = table2.field2
SELECT * FROM table1 LEFT JOIN teble2 0N tablel.field1 = table2.field2

数据库中的数据表格之间往往有一定的联系,例如学生考试成绩数据库中,用数据表格table1 来存储学号,姓名、语文成绩、数学成绩,而物理成绩和化学成绩只是用学号来标记,并没有给出成绩,用数据表格 table2 存储学号姓名、物理成绩和化学成绩如果想通过查询数据表格 tablel 得到语文成绩、数学成绩、物理成绩和化学成绩,就可利用QSqlRelationalTableModel模型的外键功能来实现。

关系表格模型QSglRelationalTableModel官方说明

QSqlRelationalTableModel的作用类似于QSqlTableModel,但允许将列设置为其他数据库表的外键。

noforeignkeys1foreignkeys2

左边的屏幕截图显示了一个QTableView中的普通QSqlTableModel。外键(城市和国家)无法解析为人类可读的值。右边的屏幕截图显示了一个QSqlRelationalTableModel,其中外键被解析为人类可读的文本字符串。
以下代码片段显示了如何设置QSqlRelationalTableModel:

model.setTable("employee")
model.setRelation(2, QSqlRelation("city", "id", "name"))

函数调用setRelation()在两个表之间建立关系。第一个调用指定employee表中的列2是一个外键,它与表city的字段id映射,并且视图应该向用户显示城市的名称字段。第二个调用对第3列执行类似的操作。
如果使用读写QSqlRelationalTableModel,则可能需要在视图上使用QSqlRelationsDelegate。与默认委托不同,QSqlRelationalDelegate为作为其他表外键的字段提供了一个组合框。要使用该类,只需在具有QSqlRelationalDelegate实例的视图上调用setItemDelegate():

std.unique_ptr<QTableView> view{QTableView()}
view.setModel(model)
view.setItemDelegate(QSqlRelationalDelegate(view.get()))

relationaltablemodel示例说明了如何将QSqlRelationalTableModel与QSqlRelationalDelegate结合使用,为表提供外键支持。

../../_images/relationaltable.png

说明:

  • 该表必须声明一个主键。
  • 表的主键不能包含与另一个表的关系。
  • 如果关系表包含引用被引用表中不存在的行的键,则包含无效键的行将不会通过模型公开。用户或数据库负责保持引用的完整性。
  • 如果关系的显示列名也用作关系表中的列名,或者如果它在多个关系中用作显示列名,则它将被别名化。别名是关系的表名、显示列名和由下划线连接的唯一id(例如tablename_columnname_id)。
  • fieldName()将返回别名列名。当检测到重复时,所有重复显示列名的出现都会产生别名,但不会对主表中的列名产生别名。别名不会影响QSqlRelation,因此displayColumn()将返回原始显示列名。
  • 引用表名称是别名。别名是单词"relTblAl"和由下划线连接的相关列索引(例如relTblAl_2)。别名可用于筛选表(例如,setFilter(“relTblAl_2='Oslo’或relTblAl_3=‘USA’”)。
  • 使用setData()时,角色应始终为EditRole,使用data()时角色应始终是DisplayRole。
关系表格模型QSglRelationalTableModel方法介绍

用QSqlRelationalTableModel类创建关系表格模型的方法如下所示

from PySide6.QtSql import QSqlRelationalTableModel

QSqlRelationalTableModel(parent: Union[PySide6.QtCore.QObject,NoneType] = None,db: PySide6.QtSql.QSqlDatabase = Default(QSqlDatabase))-> None
  • 用QSqlRelationalTableModel 的 setRelation(column:int,relation: QSqlRelation)方法定义QSqlRelationalTableModel 当前数据表格(如 table1)的外键和映射关系,
    • 其中参数column 是 tablel的字段编号,用于确定 tablel 中当作外键的字段 field1
    • relation 参数是QSgIRelation的实例对象,用于确定另外一个数据表格(如 table2)和对应的字段 field2.
  • QSqlRelation实例对象的创建方法是 QSqlRelation(tableName: str,indexCol;strdisplayCol:str)
    • 其中tableName 用于确定第2个数据表格 table2,
    • indexCol用于指定table2 的字段 feld2,
    • displayCol是 table2 中用于显示在 tablel 的 field1位置处的字段 field3,用field3 的值显示在 field1 位置处,field1 的值不显示
  • 另外用QSlRelationalTableModel 的setJoinMode(joinMode: QSgIRelationalTableModel,JoinMode)方法可设置两个数据表格的数据映射模式,参数joinMode可取 :
    • QSqlRelationalTableModel.InnerJoin(内连接,值为0,只列出 tablel和 table2 中匹配的数据)
    • QSqlRelationalTableModel.LeftJoin(左连接 值为1,即使 tablel和 table2 没有匹配的数据也列出 tablel中的数据)。

外键使用方法如下:

model = QSqlRelationalTableModel()
model.setTable("employee")
model.setRelation(2,QSqlRelation("city","id","name"))
model.setRelation(3,QSqlRelation("country","id","name"))
示例

本案例建立了3个表,第1个表包含本案例想要展示的所有内容,其他两个表都是用来对比的。下面对本案例的代码进行简要介绍。

本案例使用的数据库涉及 student2、sex 和 subject 这3个表的内容。其文件放在database.db中

第1个表和第2个表使用同一个模型实例,所以它们的变化完全同步。第1个表和第2个表的不同之处是,第1个表使用 QSqlRelationalDelegate 委托,并为视图创建了良好的编辑体验。这个委托的使用方式如下:

self.tableView.setItemDelegate(QSqlRelationalDelegate(self.tableView))

第1个表和第3个表使用同一个模型的不同实例对象,所以数据变化不会同步;因为第3个表的模型没有设置外键,所以该表就是一个普通表格,是第1个表原始的样子。第1个表的外键的使用方式如下:

self.model.setTable("student2")
self.model.setRelation(2,QSqlRelation("sex","id","name"))
self.model.setRelation(3,QSqlRelation("subject","id","name"))

下面对上述代码进行解释:以第2行为例,setRelation)函数指定第3列(列编号从0开始)作为 student2 表的外键,QSqlRelation 将这个外键与 sex表的id对应,但是它会显示为sex表的name,也就是会显示为"男"或"女"。

from PySide6.QtWidgets import *
from PySide6.QtGui import *
from PySide6.QtCore import *
from PySide6.QtSql import QSqlDatabase,QSqlRelationalTableModel,QSqlRelation,QSqlRelationalDelegate
import sys
import os

os.chdir(os.path.dirname(__file__))


class SqlRelationalTableDemo(QMainWindow):

    def __init__(self,parent=None):
        super(SqlRelationalTableDemo,self).__init__(parent)
        self.setWindowTitle("QSqlRelationalTableModel案例")
        self.resize(550,600)
        self.initModel()
        self.createWindow()

    def initModel(self):
        self.model = QSqlRelationalTableModel()
        self.model.setTable("student2")
        self.model.setRelation(2,QSqlRelation("sex","id","name"))
        self.model.setRelation(3,QSqlRelation("subject","id","name"))
        self.model.setHeaderData(0,Qt.Horizontal,"编号")

        self.model.setHeaderData(1,Qt.Horizontal,"姓名")
        self.model.setHeaderData(2,Qt.Horizontal,"性别")
        self.model.setHeaderData(3,Qt.Horizontal,"科目")
        self.model.setHeaderData(4,Qt.Horizontal,"成绩")
        self.model.select()

    def createWindow(self):
        self.tableView = QTableView()
        self.tableView.setModel(self.model)
        self.tableView.setItemDelegate(QSqlRelationalDelegate(self.tableView))
        self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        self.tableView2 = QTableView()
        self.tableView2.setModel(self.model)
        self.tableView2.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        self.tableView3 = QTableView()
        model3 = QSqlRelationalTableModel()
        model3.setTable('student2')
        model3.select()
        self.tableView3.setModel(model3)
        self.tableView3.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        layout = QVBoxLayout()
        layout.addWidget(self.tableView)
        layout.addSpacing(10)
        layout.addWidget(self.tableView2)
        layout.addSpacing(10)
        layout.addWidget(self.tableView3)
        widget = QWidget()
        self.setCentralWidget(widget)
        widget.setLayout(layout)


if __name__ =="__main__":
    app = QApplication(sys.argv)
    db = QSqlDatabase.addDatabase('QSQLITE')
    db.setDatabaseName('./db/database.db')
    if db.open()is not True:
        QMessageBox.critical(QWidget(),"警告","数据连接失败,程序即将退出")
        exit()
    demo = SqlRelationalTableDemo()
    demo.show()
    sys.exit(app.exec())

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

士别三日,当挖目相待

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值