在模型-视图-控制器模式中使用 ObjectListView,在 Python 中使用 SQLAlchemy

Use ObjectListView in the Model-View-Controller pattern with SQLAlchemy in Python

我在考虑如何将 ObjectListView fitting the Model-View-Controller Pattern 与 wxPython 和 SQLAlchemy 一起使用。我不确定,所以我创建了一个简单的示例作为工作基础而不是解决方案。

与下面代码相关的具体问题是:如果生成一个新的 MyData 对象会发生什么?

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import wx
import sqlalchemy as sa
import sqlalchemy.ext.declarative as sad
import ObjectListView as olv

_Base = sad.declarative_base()

class MyData(_Base):
    """the database table representing class"""
    __tablename__ = 'MyData'

    __name = sa.Column('name', sa.String, primary_key=True)
    __count = sa.Column('count', sa.Numeric(10, 2))

    def __init__(self, name, count):
        super(MyData, self).__init__()
        self.__name = name
        self.__count = count

    def GetName(self):
        return self.__name

    def GetCount(self):
        return self.__count


def CreateData():
    """
        helper creating data

        imagnine this as a SELECT * FROM on the database
    """
    return [
        MyData('Anna', 7),
        MyData('Bana', 6)
        ]


class MyView(olv.ObjectListView):
    def __init__(self, parent):
        super(MyView, self).__init__(parent, wx.ID_ANY, style=wx.LC_REPORT)
        self.SetColumns([
            olv.ColumnDefn('Name', valueGetter='GetName'),
            olv.ColumnDefn('Count', valueGetter='GetCount')
            ])
        data = CreateData()
        self.SetObjects(data)


    def ColDef(self):
        return 

class MyApp(wx.App):
    def OnInit(self):
        frame = wx.Frame(None)
        view = MyView(frame)
        frame.Show()
        return True


if __name__ == '__main__':
    app = MyApp()
    app.MainLoop()

你在想什么... 创建一个控制器 "MyDataController" 来处理 MyData 对象的所有 sqlalchemy-stuff。例如GetAllMyDataObjects AddMyDataObjectToDatabase, QueryMyData, ... 与Observer-Pattern相关的是ObjectListView观察者控制器作为主体。 我不确定这是否是一个优雅的解决方案。 关键是混淆,什么是模型?一个(和新的)MyData 实例还是所有 MyData 实例的列表?没有智能列表可以作为模型。

关于OLV。在我的例子中,当 SA 模型发生更新时,我使用 pubsub 向全世界通报更改 add/update/delete。

然后我的OLV基地class订阅了'itemAdded'、'itemModified'和'itemDeleted'消息,下面是调用的方法:

def pubListItemAdded(self, dbitem):
    """
    Add list if dbitem instance matches dbScKlass

    :param dbitem: an SA model instance

    If dbitem instance matches the list controls model it is added.
    """
    # protect from PyDeadObjectError
    if self:
        # E.g. Externalimp is a faked class and does not exist in db
        # so we need to protect for that
        if hasattr(db, self._klassName):
            tList = self.getList()
            cInst = getattr(db, self._klassName)
            if isinstance(dbitem, cInst):
                log.debug("olvbase - added: %s", dbitem)
                log.debug("olvbase - added: %s", self)
                # for some reason this creates dups on e.g. rating/tasting/consumption
                # so, lets check if it is there and only add if not
                idx = tList.GetIndexOf(dbitem)
                if idx == -1:
                    tList.AddObject(dbitem)
                else:
                    tList.RefreshObject(dbitem)

                # bring it into view
                self.resetSelection()
                tList.SelectObject(dbitem, deselectOthers=True,
                                   ensureVisible=True)

def pubListItemModified(self, dbitem):
    """
    Update list if dbitem instance matches dbScKlass

    :param dbitem: an SA model instance

    If dbitem instance matches the list controls model it is updated.
    """
    # protect from PyDeadObjectError
    if self:
        # E.g. Externalimp is a faked class and does not exist in db
        # so we need to protect for that
        if hasattr(db, self._klassName):
            cInst = getattr(db, self._klassName)
            if isinstance(dbitem, cInst):
                log.debug("olvbase - modified: %s", dbitem)
                log.debug("olvbase - modified: %s", self)
                tList = self.getList()
                # need to refresh to ensure relations are loaded
                wx.GetApp().ds.refresh(dbitem)
                tList.RefreshObject(dbitem)
                tList.SelectObject(dbitem, deselectOthers=True,
                                    ensureVisible=True)
                # deselect all, so if we select same item again
                # we will get a select event
                tList.DeselectAll()

def pubListItemDeleted(self, dbitem):
    """
    Delete from list if dbitem instance matches dbScKlass

    :param dbitem: an SA model instance

    If dbitem instance matches the list controls model it is updated.
    """
    # protect from PyDeadObjectError
    if self:
        # E.g. Externalimp is a faked class and does not exist in db
        # so we need to protect for that
        if hasattr(db, self._klassName):
            cInst = getattr(db, self._klassName)
            if isinstance(dbitem, cInst):
                log.debug("olvbase - deleted: %s", dbitem)
                log.debug("olvbase - deleted: %s", self)
                tList = self.getList()
                tList.RemoveObject(dbitem)
                self.currentObject = None
                self.currentItemPkey = None