Thank You for the explanation!
As you said I had to implement the roleNames() Function and adjusted the data().
The code below now works
import sys import typing import PySide6 from PySide6 import QtCore from PySide6 import QtGui from PySide6.QtCore import QByteArray class ProductListModel (QtCore.QAbstractListModel): def __init__(self, products, parent = None): super().__init__(parent) self.products = products def data(self, index, role): """Returns an appropriate value for the requested data. If the view requests an invalid index, an invalid variant is returned. Any valid index that corresponds to a string in the list causes that string to be returned.""" row = index.row() if not index.isValid() or row >= len(self.products): return None product = self.products[row] if role == QtCore.Qt.DisplayRole: return product.name elif role == QtCore.Qt.EditRole: return product.name elif role == QtCore.Qt.UserRole + 1: return product.id elif role == QtCore.Qt.UserRole + 2: return product.name return None def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole): """Returns the appropriate header string depending on the orientation of the header and the section. If anything other than the display role is requested, we return an invalid variant.""" if role != QtCore.Qt.DisplayRole: return None if orientation == QtCore.Qt.Horizontal: return f"Column {section}" return f"Row {section}" def rowCount(self, parent: typing.Union[PySide6.QtCore.QModelIndex, PySide6.QtCore.QPersistentModelIndex] = ...) -> int: # return length of productList return len(self.products) def roleNames(self): roles = { QtCore.Qt.UserRole + 1: b'id', QtCore.Qt.UserRole + 2: b'name', } return roles class Product: def __init__(self, id:int, name:str): self.id = id self.name = name```