9

这是对这个问题的跟进。在那里,我们创建了 QSqlQueryModel 的可编辑子类,用于复杂查询。现在我需要添加 QTableModel 的 setEditStrategy 之类的功能,这样我就可以缓存所有更改并使用按钮接受或恢复它们。PyQt 显然不允许多重继承,我找不到足够的文档来在我的自定义模型中重新实现此方法,因此这里有一个问题:

如何在可编辑的 QSqlQueryModel 中重新实现 QSqlTableModel.setEditStragety(或类似的东西),包括 RevertAll() 和 SubmitAll()?

这是一个 CVME:(我已经对我想开始工作的示例类的部分进行了注释)

import sys

from PyQt5.QtCore import Qt
from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel, QSqlTableModel
from PyQt5.QtWidgets import QApplication, QTableView, QWidget, QGridLayout
from PyQt5.Qt import QPushButton

db_file = "test.db"


def create_connection(file_path):
    db = QSqlDatabase.addDatabase("QSQLITE")
    db.setDatabaseName(file_path)
    if not db.open():
        print("Cannot establish a database connection to {}!".format(file_path))
        return False
    return True


def fill_tables():
    q = QSqlQuery()
    q.exec_("DROP TABLE IF EXISTS Manufacturers;")
    q.exec_("CREATE TABLE Manufacturers (Company TEXT, Country TEXT);")
    q.exec_("INSERT INTO Manufacturers VALUES ('VW', 'Germany');")
    q.exec_("INSERT INTO Manufacturers VALUES ('Honda' , 'Japan');")

    q.exec_("DROP TABLE IF EXISTS Cars;")
    q.exec_("CREATE TABLE Cars (Company TEXT, Model TEXT, Year INT);")
    q.exec_("INSERT INTO Cars VALUES ('Honda', 'Civic', 2009);")
    q.exec_("INSERT INTO Cars VALUES ('VW', 'Golf', 2013);")
    q.exec_("INSERT INTO Cars VALUES ('VW', 'Polo', 1999);")


class SqlQueryModel_editable(QSqlQueryModel):
    """a subclass of QSqlQueryModel where individual columns can be defined as editable
    """
    def __init__(self, editables):
        """editables should be a dict of format: 
        {INT editable_column_nr : (STR update query to be performed when changes are made on this column
                                   INT model's column number for the filter-column (used in the where-clause),
                                   )} 
        """
        super().__init__()
        self.editables = editables

    def flags(self, index):
        fl = QSqlQueryModel.flags(self, index)
        if index.column() in self.editables:
            fl |= Qt.ItemIsEditable
        return fl

    def setData(self, index, value, role=Qt.EditRole):
        if role == Qt.EditRole:
            mycolumn = index.column()
            if mycolumn in self.editables:
                (query, filter_col) = self.editables[mycolumn]
                filter_value = self.index(index.row(), filter_col).data()
                q = QSqlQuery(query.format(value, filter_value))
                result = q.exec_()
                if result:
                    self.query().exec_()
                else:
                    print(self.query().lastError().text())
                return result
        return QSqlQueryModel.setData(self, index, value, role)

    def setFilter(self, myfilter):
        text = (self.query().lastQuery() + " WHERE " + myfilter)
        self.setQuery(text)


class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(400, 150)

        self.createModel()
        self.initUI()

    def createModel(self):
        editables = {1 : ("UPDATE Manufacturers SET Country = '{}' WHERE Company = '{}'", 2)}
        self.model = SqlQueryModel_editable(editables)
        query = '''
            SELECT (comp.company || " " || cars.model) as Car,
                    comp.Country,
                    cars.company,
                    (CASE WHEN cars.Year > 2000 THEN 'yes' ELSE 'no' END) as this_century
            from manufacturers comp left join cars
                on comp.company = cars.company
            '''
        q = QSqlQuery(query)
        self.model.setQuery(q)
        self.model.setFilter("cars.Company = 'VW'")
#         self.model.setEditStrategy(QSqlTableModel.OnManualSubmit)

    def initUI(self):
        self.layout = QGridLayout()
        self.setLayout(self.layout)
        self.view = QTableView()
        self.view.setModel(self.model)
        self.view.hideColumn(2)
        self.layout.addWidget(self.view,0,0,1,2)

        self.accept_btn = QPushButton("Accept Changes")
#         self.accept_btn.clicked.connect(self.model.submitAll)
        self.layout.addWidget(self.accept_btn, 1,0)
        self.reject_btn = QPushButton("Reject Changes")
#         self.reject_btn.clicked.connect(self.model.revertAll)
        self.layout.addWidget(self.reject_btn, 1,1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    if not create_connection(db_file):
        sys.exit(-1)

    fill_tables()

    ex = Example()
    ex.show()
    sys.exit(app.exec_())

编辑以澄清:

我需要一个可编辑的 QSqlQueryModel,我可以在其上使用submitAll()and revertAll(),以便模型数据的更改仅在单击接受按钮后才被接受,或者可以使用“拒绝”按钮恢复。

4

0 回答 0