我試圖使用自定義集合「連接」(或相關)兩個類,但我一直無法做到這一點。也許我弄錯了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