如何使可编辑的 QTableView 显示来自复杂 SQLite 查询的数据?
我需要用来自几个 SQLite 表的数据填充 QTableView。这需要用户可编辑。
由于查询有点复杂(包括 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'")
要回答传入的问题:
可编辑性:
在此示例中,唯一绝对需要可编辑的列(以使更改到达数据库的方式)是 Country 列(并且那里的更改应该影响共享相同内容的所有其他行;例如,如果您更改任何大众汽车的“德国”到“法国”,然后都应将“法国”列为国家)。
如果您知道一种使第一个也可编辑的方法,以便更新数据库中的各个列,那将非常好看,但这不是必需的。(在我的真实表格中,我将此类“列连接”用于不可编辑的字段。)在这种特定情况下,我希望将“VW Polo”更改为“Marco Polo”也将“VW Golf”更新为“Marco Golf” ',因为列连接中使用的列是制造商.公司而不是汽车.公司。(实际上,可能会使用cars.company 进行连接,在这种情况下,'VW Golf' 将保持不变。但让我们假设上面给出的查询。)
第三列是计算统计结果的示例,这些通常仅供阅读(编辑它们没有意义)。
列顺序:
我非常感谢能够选择列的显示顺序,即使跨连接表(就像我可以使用查询一样)。