0

Im using PyQt5 to develop an MVC application using sqlite DB. I have a custom model inheriting from QAbstractTableModel. For the view im using in QTableView. In the custom model i have added function setdata() and flags() needed to make the table cells in the view editable. But when i edit the cells in the QtableView ,they do not persist in the sqlite DB. When creating the view i use setModel() function to link the view and model. What i want is a view with an editable table which on edit persists in the view and updates the sqlite database as well. eg If i edit first row for result1 column from 1.23 to 1.234,althought the View now shows 1.234, the sqlite DB shows 1.23 instead of 1.234 :-(

@musicamante Below is my code so far

from PyQt5 import QtCore, QtGui,QtWidgets
from PyQt5.QtWidgets import (
    QApplication,
    QMainWindow,
)
import sys, sqlite3
import pandas as pd
from PyQt5.QtCore import Qt

class TestUI():
    def __init__(self):
        self.db = sqlite3.connect("test.db")
        data = pd.read_sql_query("SELECT * FROM Reports",self.db)  # where Reports is the table name, which i have already created beforehand
        self.model = TableModel(data)

    def createView(self, title):
        view = QtWidgets.QTableView(self.centralwidget)
        view.setGeometry(QtCore.QRect(60, 130, 541, 301))
        view.resizeColumnsToContents()
        view.setObjectName("view")
        view.setModel(self.model)
        view.setWindowTitle(title)
        return view

    def setupUi(self, MainWindow):
        MainWindow.resize(800, 480)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.createView("TableView")
        MainWindow.setCentralWidget(self.centralwidget)


class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data):
        super(TableModel, self).__init__()
        self._data = data
        self.initializeModel()

    def initializeModel(self):
        self.setHeaderData(2, QtCore.Qt.Horizontal, "serialNo")
        self.setHeaderData(3, QtCore.Qt.Horizontal, "timestamp")
        self.setHeaderData(4, QtCore.Qt.Horizontal, "result1")


    def data(self, index, role):
        if index.isValid():
            if role == Qt.DisplayRole or role == Qt.EditRole:
                value = self._data.iloc[index.row(), index.column()]
                return str(value)

        if role == Qt.ForegroundRole or role == Qt.EditRole:
            value = self._data.iloc[index.row(), index.column()]

            if (
                    (isinstance(value, int) or isinstance(value, float))
                    and value > 0
            ):
                return QtGui.QColor('red')

    def rowCount(self, index):
        return self._data.shape[0]

    def columnCount(self, index):
        return self._data.shape[1]

    def headerData(self, section, orientation, role):
        # section is the index of the column/row.
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return str(self._data.columns[section])

            if orientation == Qt.Vertical:
                return str(self._data.index[section])

    def setData(self, index, value, role):
        if role == Qt.EditRole:
            self._data.iloc[index.row(), index.column()] = value
            return True

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


if __name__ == "__main__":
    app = QApplication(sys.argv)
    MainWindow = QMainWindow()
    ui = TestUI()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

view with table

BizBaker
  • 13
  • 4
  • We don't provide "working examples" about practices or concepts, we answer to specific questions, so please [edit] your question and provide a [mre] of *your* code so that we can help you understand why it doesn't work. – musicamante Dec 18 '21 at 16:38
  • I have update the post with requested information – BizBaker Dec 20 '21 at 12:16
  • As the name suggests, `pd.read_sql_query` only ***reads*** the data from the database. After that, any modification is done on the pandas dataframe, *not* on the database. If you want to apply those changes, you should use [`to_sql()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_sql.html). Please consider that if you don't actually need pandas feature and you only want to interact with the database, using sqlite3 and pandas is pointless, as Qt already provides sql support through the QtSql module. – musicamante Dec 20 '21 at 13:13
  • @musicamante thanks for reply. I agree that Qtsql seems like a good choice. The reason why i was leaning towards panda is that i wanted to export to excel and panda has very easy api for that. I did try using QSqlDatabase and QSqlTableModel but got stuck as i need to do custom formatting to the model data shown in the View. Also couldnt find an easy way to export to excel – BizBaker Dec 21 '21 at 05:48
  • custom formatting can be done in various ways through basic subclass of the model, with a QIdentityProxyModel or an item delegate (for basic display purposes), and you can always "serialize" it by converting it to a dataframe and then use the excel export. It always depends on the needs: if the export feature is used very frequently, your approach might be better, but if database interaction is the main aspect, using QSqlDatabase is preferable as its interface is usually quite solid and reliable, especially considering that it also provides record insertion and deletion. – musicamante Dec 21 '21 at 09:33

0 Answers0