PDA

View Full Version : QSqlRelationalDelegate displays foreign_key - id instead of name/value from Combobox



GrayWizard12345
5th August 2021, 10:58
I am trying to add new rows to QSqlRelationalModel which is represented in QTableView. This new row is populated by the user, and on fieldChange should be submitted to DB.

I have set proper QSqlRelationalDelegate and proper QSqlRelations in the model:


self.table_model = QSqlRelationalTableModel(main, database)
self.table_model.setJoinMode(QSqlRelationalTableMo del.JoinMode.LeftJoin)
table_name = 'book_of_accounts'
self.table_name = table_name
self.table_model.setTable(table_name)

self.table_model.setRelation(4, QSqlRelation('account_type', 'id', 'name'))
self.table_model.setRelation(7, QSqlRelation('subconto1', 'id', 'name'))
self.table_model.setRelation(8, QSqlRelation('subconto2', 'id', 'name'))
self.table_model.setRelation(9, QSqlRelation('subconto3', 'id', 'name'))

self.table_model.setEditStrategy(QSqlTableModel.Ed itStrategy.OnFieldChange)
self.table_model.select()

self.tableView = QtWidgets.QTableView(self.verticalLayoutWidget)
self.tableView.setModel(self.table_model)
self.tableView.setItemDelegate(QSqlRelationalDeleg ate(self.tableView))





Displaying and updating existing data from the database works fine. Columns with related data change to Comboboxes and I can choose options from the related tables.

However, when I try to create a new record by adding a row to the model, Comboboxes allow me to choose the proper value from the dropdown list, but after choosing it, the value changes to the ID of the related record as if no relational delegate was set:



def addRow(self):
count = self.table_model.rowCount(QModelIndex())
self.table_model.insertRows(count, 1)
self.tableView.scrollToBottom()
self.tableView.selectRow(count)



Here is how I can choose a correctly displayed option:
13699

But once I close the editor, the text is replaced with a foreign key:
13698

Once I fill out all fields and select another row, the data is submitted and the row is displayed correctly again. So this only happens while adding a new row.

I am using a QFilterSortProxyModel too, but it has no effect on the described behavior. This bug is persistent in both pyqt5 and pyqt6.

While debugging I discovered that in QSqlRelationalDelegate`s setModelData, model.data() contains the corresponding foreign keys when the method is executed.

I have a SO question (https://stackoverflow.com/questions/68634621/qsqlrelationaldelegate-displays-foreign-key-id-of-the-related-record-instead-o), which describes the problem with a bit more code as context.

Am I missing something obvious here? How can tackle this issue?

ecanela
24th December 2023, 05:13
short answer: QFilterSortProxyModel cant work using a proxy model.

long answer: need to subclass QSqlRelationalDelegate to search in the proxy mode, the source model. and call the base function using the model and index if the sourceModel()

1- need to find the first not-proxy model using the 'index', and the mapped model index related to proxy index 'index' and return the source model index and the index mapped from the proxy model


std::tuple<QAbstractItemModel *, QModelIndex> findSourceModel(QModelIndex index) const
{
QAbstractItemModel * source_model = (QAbstractItemModel *)index.model();
QModelIndex source_index = index;

while( source_model->inherits("QAbstractProxyModel") ){
//qDebug() << "class name from proxy model " << source_model->metaObject()->className();
source_index = static_cast<QAbstractProxyModel *>(source_model)->mapToSource(source_index);
source_model = static_cast<QAbstractProxyModel *>(source_model)->sourceModel();
}

return {source_model, source_index};
}


and use the returned values whit the base class implementation of QSqlRelationalDelegate



QWidget *QSqlRelationalProxyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
auto[source_model, source_index] = findSourceModel(index);
return QSqlRelationalDelegate::createEditor(parent,option ,source_index);
}


NOTE:
for a not proxy model. i refer to any subclass of QAbstractProxyModel, mainly a QSortProxyModel or QIdentityProxyModel subclass

I apologize for responding with a code in C++, but I haven't programmed in Python for a long time, it should be easy to convert it to Python.
I hope it is useful to you