QTableView editable de consulta SQL compleja

¿Cómo puedo hacer un QTableView editable que muestre datos de una consulta SQLite compleja?

Necesito llenar un QTableView con datos de varias tablas SQLite. Esto debe ser editable por el usuario.

Como las consultas son un poco complejas (incluidas JOINs y CASE WHEN, etc.), lo hago a través de un QSqlTableModel y un QSqlQuery. Sin embargo, me han dicho que no es así como se debe usar QSqlTableModels. Entonces, ¿alguien puede mostrarme cómo obtener un resultado como el que se muestra aquí de la manera correcta?

Además, aunque mis QTableViews son editables, los resultados no parecen almacenarse en la base de datos SQLite. (Cuando comento fill_tables, sigo obteniendo los resultados originales después de reiniciar la GUI. Cambiar EditStrategy a OnFieldChange no ayuda). ¿Es porque estoy manejando QSqlTableModel mal?

#!/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()

Intenté usar un QSqlRelationalTableModel en su lugar, pero no puedo hacer la misma complejidad de consultas, y tampoco guarda los cambios, al igual que el código anterior. Esto es hasta donde llegué a ese intento:

     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'")

Para responder preguntas entrantes:

Editabilidad:

En este ejemplo, la única columna que definitivamente esnecesario para que sea editable (de tal manera que los cambios lleguen a la base de datos) es la columna País (y los cambios allí deberían afectar a todas las demás filas que comparten el mismo contenido; por ejemplo, si cambia 'Alemania' a 'Francia' para cualquiera de VW- coche, ambos deben enumerar 'Francia' como país).

Si conoce una forma de obtener el primero editable también, de modo que las columnas respectivas en la base de datos se actualicen, sería realmente ingenioso verlo, pero no es un requisito. (En mis tablas reales, uso tales 'uniones de columnas' para campos no editables). En este caso específico, esperaría un cambio de 'VW Polo' a 'Marco Polo' para actualizar también 'VW Golf' a 'Marco Golf ', ya que la columna utilizada en la unión de columnas es la empresa fabricantes y no la empresa automóviles. (En realidad, uno probablemente usaría cars.company para la unión, en cuyo caso 'VW Golf' permanecería sin cambios. Pero supongamos que la consulta se da como se indicó anteriormente).

La tercera columna se entiende como un ejemplo de un resultado estadístico calculado, y estos generalmente son solo para leer (editarlos no tendría sentido).

Orden de columna:

me gustaríamuy agradecería poder elegir el orden en el que se muestran las columnas, incluso en las tablas unidas (como podría hacer con la consulta).

Respuestas a la pregunta(2)

Su respuesta a la pregunta