QTableView и пользовательский ORM - PullRequest
0 голосов
/ 29 ноября 2011

У вас есть идеи, примеры, как использовать QTableView с пользовательским ORM, написанным на Python (например, Web2Py DAL).

Итак, у меня есть результат запроса и поля, описывающие свойства столбцовв результате:

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

Я хочу создать класс ResultSetModel, который можно привязать к QTableView.У меня может быть много объектов этого класса, каждый со своим запросом - как в QSqlQueryModel.Но QSqlQueryModel имеет дело с инфраструктурой SQL в Qt, но у меня есть собственный ORM для работы с базой данных.

Спасибо

ОБНОВЛЕНИЕ:

Предположим, у меня есть таблица с большим количеством строк.Я не хочу просить их всех и держать их в модели.Мне нужна модель, которая работает вместе с QTableView, запрашивая следующие или предыдущие записи, когда пользователь прокручивает представление вверх или вниз.

QAbstractItemModel.fetchMore интересно, но не делает то, что я хочу.

Вы можете увидеть пример Fetch More в examples/itemviews/fetchmore.py.Когда вы прокручиваете страницу до конца, она запрашивает дополнительную часть данных, но также сохраняет старые записи.И это не делает то же самое, когда вы прокручиваете вверх.

Представьте, что у меня в таблице Персоны несколько миллионов человек.Я хочу запрашивать и хранить в своей модели / памяти только записи, показанные в представлении.

То, чего я пытаюсь достичь, показано здесь: http://www.youtube.com/watch?v=hQlE0rrr7wI

Т.е. после того, как представление отображаетсябазовая модель запрашивает столько строк, сколько необходимо для отображения на экране.При прокрутке вниз / вверх - другие строки запрашиваются из БД постепенно.

1 Ответ

1 голос
/ 02 декабря 2011

Вот рабочий пример использования эликсира и pyside. Там должно быть где-то session.commit() (при нажатии кнопки "сохранить" или что-то в этом роде) Кроме того, он полностью функционален

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