我试图使用自定义集合“连接”(或相关)两个类,但我一直无法做到这一点。也许我弄错了SqlAlchemy custom collections的整个概念,但让我解释我在做什么(并看看有人能给我一个提示,或某事)使用从字典()与SqlAlchemy扩展自定义集合
我有一个父类(你会记得一些其他问题),其中有几个连接器字段(列表类型)。其中一个连接器将存储类型为“VR”的Child()类的实例,另一个将存储具有“CC”类型的子级。
我真的不需要持久化存储子对象的集合,但我需要它是一个特殊的类,所以它会有一些我已经实现的方法,并且需要在那里。这将是“ZepConnector”类(为了举例的目的,它的方法foo()是我需要使用的)。正如您在以下几行中看到的那样,我在Parent的addChild1()方法中随机测试其可用性。
--------------------- Parent.py -----------------
from megrok import rdb
from sqlalchemy import Column
from sqlalchemy import and_
from sqlalchemy.orm import relationship
from sqlalchemy.types import Integer
from sqlalchemy.types import String
from mylibraries.database.tests.Child import Child
from mylibraries.database.tests.Tables import testMetadata
from mylibraries.database.tests.ZepConnector import ZepConnector
class Parent(rdb.Model):
rdb.metadata(testMetadata)
rdb.tablename("parents_table")
rdb.tableargs(schema='test2', useexisting=False)
id = Column("id", Integer, primary_key=True, nullable=False, unique=True)
_whateverField1 = Column("whatever_field1", String(16)) #Irrelevant
_whateverField2 = Column("whatever_field2", String(16)) #Irrelevant
child1 = relationship(
"Child",
uselist=True,
primaryjoin=lambda: and_((Parent.id == Child.parent_id), (Child.type == "VR")),
collection_class=ZepConnector("VR")
)
child2 = relationship(
"Child",
uselist=True,
primaryjoin=lambda: and_((Parent.id == Child.parent_id), (Child.type == "CC")),
collection_class=ZepConnector("CC")
)
def __init__(self):
print "Parent __init__"
self._whateverField1 = "Whatever1"
self._whateverField2 = "Whatever2"
self.child1 = ZepConnector("VR")
self.child2 = ZepConnector("CC")
def addChild1(self, child):
if isinstance(child, Child):
print("::addChild1 > Testing .foo method: " + str(self.child1.foo()))
# The line above doesn't really makes much
# but testing the accessibility of the .foo() method.
# As I'll explain later, it doesn't work
self.child1.append(child)
def addChild2(self, child):
if isinstance(child, Child):
self.child2.append(child)
请注意,我正在使用megrok。对于那些不熟悉它的人,请允许我解释一下,它仅仅是一个将Python类映射到SqlAlchemy映射器本身的工具,并且在使用Grok framework时使它更加“程序员友好型”。
我猜父()类的常规SQLAlchemy的映射将类似这样的:
mapper(Parent, parents_table, properties={
id = Column("id", Integer, primary_key=True, nullable=False, unique=True)
_whateverField1 = Column("whatever_field1", String(16)) #Irrelevant
_whateverField2 = Column("whatever_field2", String(16)) #Irrelevant
child1 = relationship(# etc, etc, etc
})
#
但我100%...呃... 90%...呃.. 70%的人认为使用该工具并不是什么导致我问我在这里要问什么(我的意思是:我不认为是在干涉SqlAlchemy Custom Collections的事情)
一个孩子是一个非常简单课:
--------------- Child.py ------------------------- -
import random
from megrok import rdb
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy.types import Integer
from sqlalchemy.types import String
from mylibraries.database.tests.Tables import testMetadata
class Child(rdb.Model):
rdb.metadata(testMetadata)
rdb.tablename("children_table")
rdb.tableargs(schema='test2', useexisting=False)
parent_id = Column("parent_id", Integer, ForeignKey("test2.parents_table.id"), primary_key=True)
type = Column("type", String(2), nullable=True, primary_key=True)
hasher = Column("hasher", String(5))
def __init__(self):
self.type = None
self.hasher = self.generateHasher()
def setType(self, typeParameter):
if typeParameter in set(["VR", "CC"]):
self.type = typeParameter
@staticmethod
def generateHasher():
retval = str()
for i in random.sample('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 5):
retval += i
return retval
比方说,每一个孩子实例都会有一个独特的“散列器”字段,可以用来作为在字典中键(上面的例子是远离现实,但它说明了一点如何孩子将工作,并能够创建一个测试)
现在我的自定义连接器。我希望它的行为如同列表或集合(更像是集合,虽然我不介意),但它是一个继承自字典的类。
-------------------- ZepConnector。PY --------------------
from sqlalchemy.orm.collections import collection
class ZepConnector(dict):
__emulates__ = list
def __init__(self, type):
self.type = type
# The 'type' will be "VR" or "CC" and it will be stamped
# on every Child() class added through this ZepConnector
def foo(self):
return True
@collection.appender
def append(self, item):
#Appends a child to itself
if self.foo():
item.setType(self.type)
self[item.hasher] = item
@collection.remover
def remove(self, item):
try:
del self[item.hasher]
except ValueError, e:
print("::remove > Got exception when trying to remove entry=" + str(item.hasher) + ". The exception is: " + str(e))
def extend(self, items):
pass
但我不知道为什么,在父类中唐 “ZepConnector” 实例”不像是会是一个“ZepConnector”型,而是“InstrumentedList‘的:
当家长的addChild1方法()我试图测试包含.foo()方法(它应该只是打印’真“)我得到这个错误:
AttributeError: 'InstrumentedList' object has no attribute 'foo'
显示整个回溯:
Traceback (most recent call last):
File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 134, in publish
result = publication.callObject(request, obj)
File "/home/ae/mytests-cms/grokserver/eggs/grok-1.1rc1-py2.4.egg/grok/publication.py", line 89, in callObject
return super(ZopePublicationSansProxy, self).callObject(request, ob)
File "/home/ae/mytests-cms/grokserver/eggs/zope.app.publication-3.10.2-py2.4.egg/zope/app/publication/zopepublication.py", line 205, in callObject
return mapply(ob, request.getPositionalArguments(), request)
File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 109, in mapply
return debug_call(obj, args)
File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 115, in debug_call
return obj(*args)
File "/home/ae/mytests-cms/grokserver/eggs/grokcore.view-1.13.2-py2.4.egg/grokcore/view/components.py", line 101, in __call__
return mapply(self.render,(), self.request)
File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 109, in mapply
return debug_call(obj, args)
File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 115, in debug_call
return obj(*args)
File "/home/ae/mytests-cms/grokserver/src/grokserver/app.py", line 1575, in render
mylibraries.database.tests.Test.runWholeTest()
File "/home/ae/mytests-cms/mylibraries/database/tests/Test.py", line 54, in runWholeTest
__test()
File "/home/ae/mytests-cms/mylibraries/database/tests/Test.py", line 35, in __test
parent.addChild1(child)
File "/home/ae/mytests-cms/mylibraries/database/tests/Parent.py", line 54, in addChild1
print("::addChild1 > Testing .foo method: " + str(self.child1.foo()))
AttributeError: 'InstrumentedList' object has no attribute 'foo'
Debug at: http://127.0.0.1:8080/_debug/view/1289342582
很奇怪......得到正确执行ZepConnector的初始化方法......但是当我尝试使用它,它似乎并没有被ZepConnector .. 。
我做了一对夫妇的更多的测试,但都未果:
在第二次尝试我写道:
class ZepConnector(dict):
__emulates__ = set
但是这甚至使事情变得更糟,因为我得到:
在第三(或第二点二)试试,我虽然......“嗯......如果它说ZepConnector是不是列表,也许说的是家长()不使用列表中的关系,可以帮助...也许说明该collection_class是ZepConnector使得ynnecessary关系中的uselist参数......”
所以我写了:
child1 = relationship(
"Child",
uselist = False,
primaryjoin=lambda: and_((Parent.id == Child.parent_id),(Child.type == "VR")),
collection_class=ZepConnector("VR")
)
但是,这抛出了令人毛骨悚然的异常说话ab出了场,我不应该看到的和我不希望看到... ...过:-D
AttributeError: 'ZepConnector' object has no attribute '_sa_instance_state'
我使用的python2.4和SQLAlchemy的0.6.6,刚如果它是相关的。
如果有人有任何想法,指导,辅导...什么...我会很感激你跟我一起分享吧...嗯...我们... ...
预先感谢您!
(如果你已经达到了这一行,你肯定应该有一个“谢谢你”只为您的耐心阅读这个庞大的职位)
我甚至不启动理解你的代码。请减少它,分开你的问题(我确信,有不止一个),并且对每个单独的一个进行最小限度的演示。 – knitti 2010-11-09 20:36:53
@knitti>恩......我不认为我可以在其他问题上分解这个问题。主要问题可以理解为:*“我怎样才能使用我的ZepConnector类作为Parent()和Child()类之间的collection_class?”*感谢您阅读它,尽管 – BorrajaX 2010-11-09 20:47:59
我不确定,但并不完全抛出:-)你能说服包含AttributeError的完整追踪?我特别感兴趣的是,在控制流进入'sqlalchemy.util'之前的一行# – knitti 2010-11-09 21:10:48