Хорошо, это то, что вы упоминали с обобщением, я думаю, что это правильно: D

могу сделать редактируемый QTableView, отображающий данные из сложного запроса SQLite?

Мне нужно заполнить QTableView данными из нескольких таблиц SQLite. Это должно быть редактируемым пользователем.

Поскольку запросы немного сложны (включая JOIN, CASE WHEN и т. Д.), Я делаю это через QSqlTableModel и QSqlQuery. Мне сказали, однако, что это не то, как следует использовать QSqlTableModels. Итак, кто-то может показать мне, как получить результат, подобный показанному здесь, правильным способом?

Кроме того, хотя мои QTableViews являются редактируемыми, результаты, похоже, не сохраняются в базе данных SQLite. (Когда я комментирую fill_tables, я все еще получаю исходные результаты после перезапуска GUI. Изменение EditStrategy на OnFieldChange не помогает.) Это потому, что я неправильно обрабатываю QSqlTableModel?

#!/usr/bin/python3

from PyQt5.QtSql import (QSqlDatabase, QSqlQuery, QSqlTableModel, 
                         QSqlRelationalTableModel, QSqlRelation)
from PyQt5.QtWidgets import QTableView, QApplication
from PyQt5.Qt import QSortFilterProxyModel
import sys

db_file = "test.db"

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


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 CarTable(QTableView):
    def __init__(self):
        super().__init__()
        self.init_UI()
        self.create_model()

    def create_model(self):
        query = """
        SELECT (comp.company || " " || cars.model) as Car,
                comp.Country,
                (CASE WHEN cars.Year > 2000 THEN 'yes' ELSE 'no' END) as this_century
        from manufacturers comp left join cars
            on comp.company = cars.company
        """
        raw_model = QSqlTableModel()
        q = QSqlQuery()
        q.exec_(query)
        self.check_error(q)
        raw_model.setQuery(q)

        self.model = QSortFilterProxyModel()
        self.model.setSourceModel(raw_model)
        self.setModel(self.model)

        # filtering:
        self.model.setFilterKeyColumn(0)
        self.model.setFilterFixedString('VW')

    def init_UI(self):
        self.resize(500,300)

    def check_error(self, q):
        lasterr = q.lastError()
        if lasterr.isValid():
            print(lasterr.text())
            exit(1)


def main():
    mydb = create_connection(db_file)
    if not mydb:
        sys.exit(-1)
    fill_tables()
    app = QApplication(sys.argv)
    ex = CarTable()
    ex.show()
    result = app.exec_()

    if (mydb.open()):
        mydb.close()

    sys.exit(result)


if __name__ == '__main__':
    main()

Вместо этого я попытался использовать QSqlRelationalTableModel, но я не могу выполнить ту же сложность запросов, и она также не сохраняет изменения, как в коде выше. Насколько я понял в этой попытке:

     def create_model_alternative(self):
        self.model = QSqlRelationalTableModel()
        self.model.setTable("Cars")
        self.model.setRelation(0, QSqlRelation("Manufacturers", "Company",
                                               "Company, Country"))  
        self.setModel(self.model)
        self.model.select()

        # filtering:
        self.model.setFilter("cars.Company = 'VW'")

Чтобы ответить на входящие вопросы:

Возможность редактирования:

В этом примере единственный столбец, который определеннотребуется быть доступным для редактирования (таким образом, чтобы изменения поступали в базу данных) - это столбец «Страна» (и изменения там должны повлиять на все остальные строки, имеющие одинаковое содержимое; например, если вы измените «Германия» на «Франция» для любого VW- автомобиль, оба должны затем перечислить «Франция» в качестве страны).

Если вы знаете способ сделать первый доступным для редактирования, чтобы обновлять соответствующие столбцы в базе данных, это было бы очень удобно, но это не является обязательным требованием. (В моих реальных таблицах я использую такие «соединения столбцов» для не редактируемых полей.) В этом конкретном случае я ожидал бы изменить «VW Polo» на «Marco Polo», чтобы также обновить «VW Golf» на «Marco Golf». ', так как столбец, используемый в столбце-соединении, - это производители, а не cars.company. (В действительности, возможно, для соединения можно использовать cars.company, и в этом случае VW Golf останется неизменным. Но давайте предположим, что запрос приведен выше.)

Третий столбец предназначен для примера результата вычисляемой статистики, и он, как правило, предназначен только для чтения (редактировать его не имеет смысла).

Порядок столбцов:

я мог быочень ценим возможность выбирать порядок отображения столбцов даже между объединенными таблицами (как я мог бы сделать с запросом).

Ответы на вопрос(2)

Ваш ответ на вопрос