Python Forum
[PyQt] QAbstractTableModel: Indexing a list of dictionaries
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyQt] QAbstractTableModel: Indexing a list of dictionaries
#1
Hi,

I have a list of dictionaires. Something like that:

addressbook = []
address_1 = {"city": "Berlin", street": "Alexanderplatz"}
address_2 = {"city": "Munich", street": "Stachus"}
...
addressbook.append(address_1)
addressbook.append(address_2)
...
Now, I want to display that list of dictionaries in a QTableView-Widget. That Widget, will get the data from the below sub-classed QAbstractTableModel my_TableModel.
The issue is the indexing shown in the code below. The way it is done there, would work for a nested list (list of a list) ... but how to do it, if you have to deall with dictionaries which are nested in a list ...?

class my_TableModel(QtCore.QAbstractTableModel):
    def __init__(self, my_data):
        super(my_TableModel, self).__init__()
        self._my_data = my_data

    def data(self, index, role):
        if role == Qt.ItemDataRole.DisplayRole:
            return self._my_data[index.row()][index.column()] # <<--- this is not working for dictionairies nested in a list !!!

    def rowCount(self, index):
        return len(self._my_data)

    def columnCount(self, index):anzupassen
        return len(self._entgeltpunkte[0])
For any kinds of tips and hints, I would be very gratefull! Thanks in advance!!!
Reply
#2
Your dict is misssing some double quotes.

You can use pandas,

        addressbook = []
        address_1 = {"city": "Berlin", "street": "Alexanderplatz"}
        address_2 = {"city": "Munich", "street": "Stachus"}

        addressbook.append(address_1)
        addressbook.append(address_2)
        
        df = pd.DataFrame(addressbook)
example with QTableView

import sys
import pandas as pd
from PyQt5.QtCore import Qt, QAbstractTableModel, QModelIndex, QVariant
from PyQt5.QtWidgets import (QMainWindow, QTableView, QApplication, 
                              QAbstractItemView)

class PandasModel(QAbstractTableModel):
    def __init__(self, df = pd.DataFrame(), parent=None): 
        QAbstractTableModel.__init__(self, parent=None)
        self._df = df
        self.setChanged = False
        self.dataChanged.connect(self.setModified)

    def setModified(self):
        self.setChanged = True
        print(self.setChanged)

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role != Qt.DisplayRole:
            return QVariant()
        if orientation == Qt.Horizontal:
            try:
                return self._df.columns.tolist()[section]
            except (IndexError, ):
                return QVariant()
        elif orientation == Qt.Vertical:
            try:
                return self._df.index.tolist()[section]
            except (IndexError, ):
                return QVariant()

    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable

    def data(self, index, role=Qt.DisplayRole):
        if index.isValid():
            if (role == Qt.EditRole):
                return self._df.values[index.row()][index.column()]
            elif (role == Qt.DisplayRole):
                return self._df.values[index.row()][index.column()]
        return None

    def setData(self, index, value, role):
        row = self._df.index[index.row()]
        col = self._df.columns[index.column()]
        self._df.loc[row, col] = value
        self.dataChanged.emit(index, index)
        return True

    def rowCount(self, parent=QModelIndex()): 
        return len(self._df.index)

    def columnCount(self, parent=QModelIndex()): 
        return len(self._df.columns)

    def sort(self, column, order):
        colname = self._df.columns.tolist()[column]
        self.layoutAboutToBeChanged.emit()
        self._df.sort_values(colname, ascending= order == Qt.AscendingOrder, inplace=True)
        self._df.reset_index(inplace=True, drop=True)
        self.layoutChanged.emit()

class Viewer(QMainWindow):
    def __init__(self, parent=None):
      super(Viewer, self).__init__(parent)
      self.filename = ""
      self.setGeometry(0, 0, 800, 600)
      self.lb = QTableView()
      self.model =  PandasModel()
      self.lb.setModel(self.model)
      self.lb.setEditTriggers(QAbstractItemView.DoubleClicked)
      self.lb.setSelectionBehavior(self.lb.SelectRows)
      self.lb.setSelectionMode(self.lb.SingleSelection)
      self.lb.setAcceptDrops(True)
      self.setCentralWidget(self.lb)
      self.setContentsMargins(10, 10, 10, 10)
      self.statusBar().showMessage("Ready", 0)
      self.lb.setFocus()


    def loadData(self):
        addressbook = []
        address_1 = {"city": "Berlin", "street": "Alexanderplatz"}
        address_2 = {"city": "Munich", "street": "Stachus"}

        addressbook.append(address_1)
        addressbook.append(address_2)
        
        df = pd.DataFrame(addressbook)
        self.model = PandasModel(df)
        self.lb.setModel(self.model)
        self.lb.resizeColumnsToContents()
        self.lb.selectRow(0)

 
if __name__ == "__main__":
 
    app = QApplication(sys.argv)
    main = Viewer()
    main.show()
    main.loadData()
    sys.exit(app.exec_())
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020