PDA

View Full Version : QSqlQueryModel write subclass



skuda
18th October 2007, 11:29
Hello, i have posted in qt-mailing list two emails with this problem but i have not get any reply, i have been searching the forum but i cant find my same problem posted, so here i go, i will post the two complete messages.

FIRST:

Hello,
i am trying to subclass QSqlQueryModel to write with it, i need this because not qsqltablemodel or
qsqlrelationaltablemodel fills my needs, i would like to do joins and insert in multiple tables, i have
implemented "flags" and "setData" methods and it works ok now, i have made a "refresh" method to reload the
contents on update because tableView not reload them with datachanged signal and all works ok but now i am
trying to implement insertrow or insertrows without luck, this is the code i am using now, it is python (i am
using pyqt) but i think is easy to read.

this in model:

def insertRows(self, position, rows=1, index=QModelIndex()):
self.beginInsertRows(QModelIndex(), position, position + rows - 1)
setdataquery = QSqlQuery(self.cursor)
setdataquery.exec_(QString("INSERT INTO SCHEMA.FAKE_TABLE (FAKE1, FAKE2, FAKE3) VALUES (4, 2, 'PEPITO')"))
self.endInsertRows()
self.dirty = True
return True

this in qdialog:

def addRecord(self):
row = self.querymodel.rowCount()
self.querymodel.insertRows(row)
index = self.querymodel.index(row, 0)
self.tableView.setCurrentIndex(index)
self.tableView.edit(index)

After execute this method i can view the new row in tableview but i get this in stdout.

edit: index was invalid
edit: editing failed

and i cant not edit the new line, i have test the row number rowCount() assign and it is ok, i dont know how
to fix this, anyone can help me please?

SECOND:

I am goin crazy with this problem, i have tested with qsqltablemodel subclassing and it works ok if a dont
write the insertRows method in the subclass, this snippets are python using PyQt:

(model subclass, this does nothing apart from inherit of QSqlTableModel)
class SkudaSqlTableModel(QSqlTableModel):
def __init__(self, dbcursor=None):
super(SkudaSqlTableModel, self).__init__()


(QDialog)
def addRecord(self):
row = self.querymodel.rowCount()
self.querymodel.insertRow(row)


this works ok and gives me an new row with an '*' in the vertical header and i can edit the line but if i do this:

(model subclass, reimplement insertRows method)
class SkudaSqlTableModel(QSqlTableModel):
def __init__(self, dbcursor=None):
super(SkudaSqlTableModel, self).__init__()

def insertRows(self, position, rows=1 , index=QModelIndex()):
self.beginInsertRows(QModelIndex(), position, position + rows - 1)
self.endInsertRows()
return True

(QDialog)
def addRecord(self):
row = self.querymodel.rowCount()
self.querymodel.insertRow(row)

i get a new line with the next number in the vertical header (not *) and i cant edit the line. So i suppose i
have any problem in my insertRows method but i have read the QSqlTableModel source code insertRows method, i
paste here the strategy OnRowchange because is what i am using.


bool QSqlTableModel::insertRows(int row, int count, const QModelIndex &parent)
{
Q_D(QSqlTableModel);
if (row < 0 || count <= 0 || row > rowCount() || parent.isValid())
return false;

switch (d->strategy) {
case OnRowChange:
if (count != 1)
return false;
beginInsertRows(parent, row, row);
d->insertIndex = row;
// ### apply dangling changes...
d->clearEditBuffer();
emit primeInsert(row, d->editBuffer);
break;
}
endInsertRows();
return true;
}

I cant find any other action to implement in my method apart from beginInsertRows and endInsertRows, i am not
using the insertIndex number (i use rowCount()), not clearEditBuffer() because i have no buffer to clear in
this test and primeInsert is a signal no connected to anything so i dont emit it, anyway i have tried using
exactly the same (all of them) in my method with exactly the same problem, can anyone please open my closed
mind with this annoying problem? i will use qsqltablemodel subclass with setQuery (inherited from QSqlQuery)
to do joins and other stuff if i cant fix this (but this is not recommended in documentation).

If anyone can open my mind i would be very pleased, i cant get to reimplement insertrows correctly, any other good way to use my own SQL queries in model/view in qt?

wysota
20th October 2007, 22:51
What database do you use? Can't you use the database to create a view of the query you wish to operate on and then use QSqlTableModel to access it from within your application?

skuda
21st October 2007, 15:27
I am using maxdb, i could create database views but with update restrictions that not ever i can get (for example i have to foreign keys between tables of the view, i would like to do so but i cant because of multimaster replication in maxdb dont allow me to do, i will have to check foreign keys in code), anyway i have got the new row, i was forgetting reimplement the rowCount() method so the index was not created with the new line in the view, i am using an edit buffer with the same columns that the sqlrecord returned, and when i add a line i add an entry to the buffer and set dirty = True and create a method to save the buffer to sql (can be called manually or on dialog close), it is working well now but i have the feeling that i could do it better than that, well i will discover in the application development i suppose :)

wysota
21st October 2007, 16:07
In my opinion you shouldn't subclass the sql query model. It might prove easier to implement a model from scratch using QAbstractTableModel or even QStandardItemModel and using QSqlQuery and/or QSqlTableModel behind the scenes. Otherwise you'll have problems with updating the model - after each change to the sql table, you'll have to use select() to fetch the updated model from the database (or it won't update), rendering the whole model-view gain practically useless, because you'll be losing selections, current items, etc.

skuda
21st October 2007, 22:56
I could use sqlquery inside the model to load a list of python objects and use it in the model, i am using this now in the editbuffer, emiting datachanged works ok with this, i could do the changes to database in background in the model, but i dont know if the speed would be good with large datasets.

wysota
21st October 2007, 23:57
I don't think it would be slower than using QSqlQueryModel directly.

skuda
29th October 2007, 16:18
Thanks for the idea wysota, i have subclassed QAstrabctTableModel and implement a buffer with the sql results and it works at good speed in my development machine, i will try with more large datasets and older machines when i implement the model in one of my customer machines.