QTableView and custom ORM
Question: Do you have any ideas, examples how to use `QTableView` with a custom ORM
written in Python (for example `Web2Py DAL`).

So i have result of a query and fields describing properties of columns in
that result:

    
    
    ID (int)  Name (str)
    1         Lisa
    2         Maria
    

I want to make a class `ResultSetModel` which can be tied to a `QTableView`. I
can have many objects of this class, each with its own query - like in
`QSqlQueryModel`. But `QSqlQueryModel` deals with SQL infrastructure in Qt,
but i have my own ORM to deal with the database.

Thank you

**UPDATE :**

Let's suppose i have a table with a lot of rows. I don't want to request all
of them and keep them in a model. I need a model that works together with
QTableView requesting next or previous records when user scrolls down or up
the view.

QAbstractItemModel.fetchMore is interesting but doesn't do what i want.

You can see the Fetch More example in `examples/itemviews/fetchmore.py`. When
you scroll down to the end, it requests additional portion of data, but keeps
the old records too. And it doesn't do the same when you scroll up.

Imagine that i have several million of persons in the Persons table. I want to
request and keep in my model/memory only the records shown in the view.

What i am trying to achieve is shown here:
<http://www.youtube.com/watch?v=hQlE0rrr7wI>

I.e. once the view is shown, the underlying model requests as many rows as
needed to show on the screen. As you scroll down/up - the other rows is
requested from DB incrementally.


Answer: Here is a working example using elixir and pyside. There should be
`session.commit()` there somewhere (on "save" button click or something like
that). Other then that it's fully functional

    
    
    from elixir import *
    from PySide import QtGui, QtCore
    import operator, sys
    
    class ColumnDescriptor(object):
        #This holds properties, controlling how each field looks/behaves in GUI"""
        def __init__(self, field_id):
            self.id = field_id
            self.verbose_name = self.id.capitalize().replace('_', ' ')
            self.comment = None
    
    class Person(Entity): #ORM entity class
        #ORM entity fields
        id_number = Field(Integer)
        name = Field(Unicode(50))
    
        def __init__(self, name, id_number):
            self.name = name
            self.id_number = id_number
    
    class PersonView():
    
        columns = []
    
        col = ColumnDescriptor('id_number')
        col.comment = "Person's identification code"
        columns.append(col)
    
        col = ColumnDescriptor('name')
        col.verbose_name = 'Full name'
        col.comment = "Person's full name"
        columns.append(col)
    
        def __init__(self):
            self.total_records = Person.query.count()
    
        def get_items(self, limit, offset = 0):
            return Person.query.offset(offset).limit(limit).all()
    
    
    class TableModel(QtCore.QAbstractTableModel):
    
        #A one-size-fits-all model based on a view descriptor
    
        numberPopulated = QtCore.Signal(int)
    
        def __init__(self, view, editable = False, limit = 50):
            super(TableModel, self).__init__()
            self.view = view
            self.editable = editable
            self.current_page = 1
            self.items_per_page = limit
            self.items = view.get_items(self.items_per_page)
    
        def columnCount(self, index):
            return len(self.view.columns)
    
        def rowCount(self, index):
            return len(self.items)
    
        def loadPage(self):
    
            self.beginResetModel()
            self.items = []
            self.endResetModel()
    
            self.items = self.view.get_items(self.items_per_page,
                self.current_page * self.items_per_page)
    
            self.beginInsertRows(QtCore.QModelIndex(), 0, len(self.items))
            self.endInsertRows()
            self.numberPopulated.emit(len(self.items))
    
        def prevPage(self):
            self.current_page = self.current_page - 1
            self.loadPage()
    
        def nextPage(self):
            self.current_page = self.current_page + 1
            self.loadPage()
    
        def headerData(self, column, orientation, role):
            if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
                return self.view.columns[column].verbose_name
    
        def data(self, index, role):
            if index.isValid():
                if (role == QtCore.Qt.DisplayRole) or (role == QtCore.Qt.EditRole):
                    field_name = self.view.columns[index.column()].id
                    value = self.items[index.row()].__getattribute__(field_name)
                    if value:
                        return unicode(value)
                    else:
                        return ''
    
        def flags(self, index):
            if not index.isValid():
                return QtCore.Qt.ItemIsEnabled
            else:
                if self.editable:
                    return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable
                else:
                    return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
    
    class MyWindow(QtGui.QWidget):
        def __init__(self):
            super(MyWindow, self).__init__()
            self.layout = QtGui.QVBoxLayout(self)
    
            self.grid = QtGui.QTableView(self)
            self.grid.setModel(TableModel(PersonView(), True))
    
            self.layout.addWidget(self.grid)
            self.layoutButtons = QtGui.QHBoxLayout(self)
            self.layout.addLayout(self.layoutButtons)
    
            self.btnPrevious = QtGui.QPushButton("Previous", self)
            self.btnNext = QtGui.QPushButton("Next",self)
            self.layoutButtons.addWidget(self.btnPrevious)
            self.layoutButtons.addWidget(self.btnNext)
    
            self.btnPrevious.clicked.connect(self.grid.model().prevPage)
            self.btnNext.clicked.connect(self.grid.model().nextPage)
    
    
    if __name__ == "__main__":
    
        metadata.bind = "sqlite:///persons.sqlite"
        setup_all(True)
    
        #fill the table up, if empty
        if not Person.query.all():
            for n in range(1,1000):
                p = Person(u'Person', n)
    
            session.commit()
    
        app = QtGui.QApplication(sys.argv)
        win = MyWindow()
        win.show()
        app.exec_()
    

