在模型-视图-控制器模式中使用 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
我在考虑如何将 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