How to display data from secondary table using PyQT Relational & data mapper

46 Views Asked by At

I am an experienced programmer but new to Python/PyQt & just trying to get my head around how the QSqlrelationship/DataWidget mapper works.

I have a main table, Tracks which links to Album table. The Album table has a link to the Artist table. I have a form using QSqlRelation with a combo box for the Album table. This works perfectly, I can scroll through each track & the correct Album name is displayed. I have a similar setup for the artist table; the combo box shows all the artists however the display sits at the first record of it & doesn't update on scrolling through the records. I suspect it's something to do with the mapping, that the model I have used for the secondary table is not being updated by the primary table. So, how do I this or is it not possible using this? I know I can do it by using a query but I'm trying to find out what is possible/not possible using the inbuilt relationship & mapping options.

Thanks

MRE below. I am using the SQLite 'chinook' demo database. As you scroll through using the next key the Artist Name does not change, however if you drop the combo down the artists are all listed.

import sys, os

from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
    QApplication, QComboBox, QMainWindow,
    QLineEdit, QWidget, QFormLayout,
    QPushButton, QDataWidgetMapper)

from PySide6.QtSql import (QSqlDatabase, QSqlTableModel,
                           QSqlRelationalTableModel, QSqlRelation,
                           QSqlRelationalDelegate)

basedir = os.path.dirname(__file__)
db = QSqlDatabase("QSQLITE")
# db.setDatabaseName(os.path.join(basedir, "chinook.sqlite"))
db.setDatabaseName('/mnt/Dev/PythonApps/PySide/SQLite_Ch20_UI/chinook.sqlite')
db.open()

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")

        layout = QFormLayout()
        edt_track = QLineEdit()
        cbo_album = QComboBox()
        cbo_artist = QComboBox()
        btn_next = QPushButton("next")

        layout.addRow("Track:", edt_track)
        layout.addRow("Album:", cbo_album)
        layout.addRow("Artist:", cbo_artist)
        layout.addWidget(btn_next)

        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        self.TrackModel = QSqlRelationalTableModel(db=db)
        self.TrackModel.setTable("Track")

        self.AlbumModel = QSqlRelationalTableModel(db=db)
        self.AlbumModel.setTable("Album")

        # Relation for AlbumId
        self.TrackModel.setRelation(2, QSqlRelation("Album", "AlbumId", "Title"))
        AlbumComboModel = self.TrackModel.relationModel(2)
        cbo_album.setModel(AlbumComboModel)
        cbo_album.setModelColumn(AlbumComboModel.fieldIndex("Title"))

        #Relation for ArtistId
        self.AlbumModel.setRelation(2, QSqlRelation("Artist", "ArtistId", "Name"))
        ArtistComboModel = self.AlbumModel.relationModel(2)
        cbo_artist.setModel(ArtistComboModel)
        cbo_artist.setModelColumn(ArtistComboModel.fieldIndex("Name"))

        self.mapper = QDataWidgetMapper()
        self.mapper.setModel(self.TrackModel)

        self.album_mapper = QDataWidgetMapper()
        self.album_mapper.setModel(self.AlbumModel)

        self.mapper.addMapping(edt_track, 1)
        self.mapper.addMapping(cbo_album, 2)
        self.album_mapper.addMapping(cbo_artist, 2)

        idx = self.TrackModel.fieldIndex("TrackId")
        self.TrackModel.setSort(idx, Qt.SortOrder.AscendingOrder)
        self.TrackModel.select()

        self.mapper.toFirst()

        while self.TrackModel.canFetchMore():
            self.TrackModel.fetchMore()

        btn_next.clicked.connect(self.mapper.toNext)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
0

There are 0 best solutions below