I am using QSortFilterProxyModels
all the time. However, if a QSqlRelation
is setup on the source model, along with a QSqlRelationalDelegate
on the view, whenever the view is switched to the proxy model, the QSqlRelationalDelegate
disappears, leaving the basic QLineEdit
or QSpinBox
.
How can I make columns in a view work with both a QSortFilterProxyModel
and QSqlRelationalDelegate
, giving the expected QCombobox
drop down?
By default, QSqlRelationalDelegate can't handle proxy models, so you have to subclass it. The below is probably far from perfect, so comments/tweaks are welcome, but has been working well on views that have a mixture of QSqlRelations/straight data, without glitches.
class ProxyDelegate(QSqlRelationalDelegate):
def __init__(self):
QSqlRelationalDelegate.__init__(self)
def createEditor(self, p, o, i): # parent, option, index
if i.model().sourceModel().relation(i.column()).isValid(): # if the column has a QSqlRelation, then make the expected QComboBox
e = QComboBox(p)
return e
else:
return QStyledItemDelegate(p).createEditor(p, o, i)
def setEditorData(self, e, i):
m = i.model()
sM = m.sourceModel()
relation = sM.relation(i.column())
if relation.isValid():
m = i.model()
sM = m.sourceModel()
relation = sM.relation(i.column())
pModel = QSqlTableModel() # pModel means populate model. Because I've aimed for generic use, it makes a new QSqlTableModel, even if one already exists elsewhere for that SQL table
pModel.setTable(relation.tableName())
pModel.select()
e.setModel(pModel)
pModel.sort(pModel.fieldIndex(relation.displayColumn()), Qt.AscendingOrder) # default sorting. A custom attribute would need adding to each source model class, in order for this line to know the desired sorting order for this QComboBox delegate
e.setModelColumn(pModel.fieldIndex(relation.displayColumn()))
e.setCurrentIndex(e.findText(m.data(i).toString()))
else:
return QStyledItemDelegate().setEditorData(e, i)
def setModelData(self, e, m, i):
m = i.model() # this could probably be written more elegantly so you don't need to create another SqlModel
sM = m.sourceModel()
relation = sM.relation(i.column())
table = relation.tableName()
indexColumn = relation.indexColumn()
indexColumnId = sM.fieldIndex(indexColumn)
displayColumn = relation.displayColumn()
if relation.isValid():
pModel = QSqlTableModel()
pModel.setTable(relation.tableName())
pModel.select()
displayColumnId = pModel.fieldIndex(displayColumn)
chosenRowInPModel = pModel.match(pModel.index(0, displayColumnId), Qt.DisplayRole, e.currentText())[0].row()
chosenIdInPModel = pModel.data(pModel.index(chosenRowInPModel, indexColumnId)).toString()
m.setData(i, chosenIdInPModel)
self.closeEditor.emit(e, QAbstractItemDelegate.NoHint)
else:
QStyledItemDelegate().setModelData(e, m, i)