Implementing setEditStrategy in editable QSqlQueryModel










6















This is a follow-up to this question. In there, we created an editable subclass of QSqlQueryModel, to use with complex queries.
Now I need to add a functionality like QTableModel's setEditStrategy so I can cache all changes and accept or revert them using buttons. PyQt apparently doesn't allow multiple inheritance and I cannot find sufficient documentation to re-implement this method in my custom model, therefor here's the question:



How can I re-implement QSqlTableModel.setEditStragety (or something like it) including RevertAll() and SubmitAll() in an editable QSqlQueryModel?



Here's a CVME: (I have out-commented the parts of of my Example class I would like to get working)



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_())


Edit to clarify:



I need an editable QSqlQueryModel, on which I can use submitAll() and revertAll(), so that changes to the model's data are only accepted after an Accept-button is clicked, or can be reverted using a "Reject" button.










share|improve this question
























  • @scopchanov I thought that was clear from the example provided. I have added explicit requirements now. Better?

    – CodingCat
    Nov 16 '18 at 9:06















6















This is a follow-up to this question. In there, we created an editable subclass of QSqlQueryModel, to use with complex queries.
Now I need to add a functionality like QTableModel's setEditStrategy so I can cache all changes and accept or revert them using buttons. PyQt apparently doesn't allow multiple inheritance and I cannot find sufficient documentation to re-implement this method in my custom model, therefor here's the question:



How can I re-implement QSqlTableModel.setEditStragety (or something like it) including RevertAll() and SubmitAll() in an editable QSqlQueryModel?



Here's a CVME: (I have out-commented the parts of of my Example class I would like to get working)



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_())


Edit to clarify:



I need an editable QSqlQueryModel, on which I can use submitAll() and revertAll(), so that changes to the model's data are only accepted after an Accept-button is clicked, or can be reverted using a "Reject" button.










share|improve this question
























  • @scopchanov I thought that was clear from the example provided. I have added explicit requirements now. Better?

    – CodingCat
    Nov 16 '18 at 9:06













6












6








6


1






This is a follow-up to this question. In there, we created an editable subclass of QSqlQueryModel, to use with complex queries.
Now I need to add a functionality like QTableModel's setEditStrategy so I can cache all changes and accept or revert them using buttons. PyQt apparently doesn't allow multiple inheritance and I cannot find sufficient documentation to re-implement this method in my custom model, therefor here's the question:



How can I re-implement QSqlTableModel.setEditStragety (or something like it) including RevertAll() and SubmitAll() in an editable QSqlQueryModel?



Here's a CVME: (I have out-commented the parts of of my Example class I would like to get working)



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_())


Edit to clarify:



I need an editable QSqlQueryModel, on which I can use submitAll() and revertAll(), so that changes to the model's data are only accepted after an Accept-button is clicked, or can be reverted using a "Reject" button.










share|improve this question
















This is a follow-up to this question. In there, we created an editable subclass of QSqlQueryModel, to use with complex queries.
Now I need to add a functionality like QTableModel's setEditStrategy so I can cache all changes and accept or revert them using buttons. PyQt apparently doesn't allow multiple inheritance and I cannot find sufficient documentation to re-implement this method in my custom model, therefor here's the question:



How can I re-implement QSqlTableModel.setEditStragety (or something like it) including RevertAll() and SubmitAll() in an editable QSqlQueryModel?



Here's a CVME: (I have out-commented the parts of of my Example class I would like to get working)



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_())


Edit to clarify:



I need an editable QSqlQueryModel, on which I can use submitAll() and revertAll(), so that changes to the model's data are only accepted after an Accept-button is clicked, or can be reverted using a "Reject" button.







python pyqt pyqt5 qsqltablemodel qsqlquerymodel






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 16 '18 at 9:06







CodingCat

















asked Sep 4 '18 at 12:31









CodingCatCodingCat

2,28852638




2,28852638












  • @scopchanov I thought that was clear from the example provided. I have added explicit requirements now. Better?

    – CodingCat
    Nov 16 '18 at 9:06

















  • @scopchanov I thought that was clear from the example provided. I have added explicit requirements now. Better?

    – CodingCat
    Nov 16 '18 at 9:06
















@scopchanov I thought that was clear from the example provided. I have added explicit requirements now. Better?

– CodingCat
Nov 16 '18 at 9:06





@scopchanov I thought that was clear from the example provided. I have added explicit requirements now. Better?

– CodingCat
Nov 16 '18 at 9:06












0






active

oldest

votes












Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52166429%2fimplementing-seteditstrategy-in-editable-qsqlquerymodel%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52166429%2fimplementing-seteditstrategy-in-editable-qsqlquerymodel%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Top Tejano songwriter Luis Silva dead of heart attack at 64

政党

天津地下鉄3号線