使用从dict()和SqlAlchemy扩展的自定义集合

2024-06-02 18:38:13 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图使用一个自定义集合来“连接”(或关联)两个类,但我没能做到。也许我把SqlAlchemy custom collections的整个概念都弄错了,但让我解释一下我在做什么(看看有没有人能给我一个暗示,或者别的什么)

我有一个父类(你们中的一些人会从其他问题中记得)在其中有几个连接器字段(列表)。其中一个连接器将存储类型为“VR”的Child()类的实例,另一个将存储类型为“CC”的子类。在

对于用于存储子对象的集合,我并不需要持久性,但我需要它是一个特殊的类,这样它将有一些我已经实现的方法,并且需要在那里。这将是“ZepConnector”类(在本例中,我需要使用的是foo()方法)。正如您在下面几行中看到的,我在父对象的addChild1()方法中随机测试它的可用性。在

------------------父级.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)

请注意,我用的是美卓克。对于那些不熟悉它的人,请允许我解释一下,它只是一个工具,它将Python类映射到SqlAlchemy映射器本身,并使它在使用Grok framework时更加“程序员友好”。在

我想常规SqlAlchemy中Parent()类的映射类似于:

^{pr2}$

但我百分之百。。。呃。。。90%。。。呃。。。70%的人确信使用这个工具并不是我要问的问题(我的意思是:我不认为这会干扰SqlAlchemy自定义集合的事情)

孩子很简单:

———————————————————————————————————————————————————————————————————————————————————————————————————————————————儿童.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

假设每个子实例都有一个惟一的“hasher”字段,可以用作字典中的键(上面的示例与实际情况相差甚远,但它稍微说明了子实例如何工作以及能够创建测试)

现在是我的自定义连接器。我希望它表现为一个列表集合(更像集合,尽管我不太在意),但它是一个继承自dict的类

------------------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”:

在Parent()的addChild1方法中,我尝试测试.foo()方法(应该只打印“True”)时,我得到以下错误:

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的init方法已正确执行。。。但当我尝试使用它时,它似乎不是ZepConnector。。。在

我又做了几次测试,但都不成功:

在第二次尝试中,我写道:

class ZepConnector(dict):
    __emulates__ = set

但这甚至让事情变得更糟,因为我得到:

TypeError: Incompatible collection type: ZepConnector is not list-like

在第三次(或第二次)尝试中,我想好。。。如果说ZepConnector不是一个列表,那么告诉Parent()不要在关系中使用列表可能会有帮助。。。也许声明collection_类是一个ZepConnector会使yn在关系中成为uselist参数…”

所以我写了:

child1 = relationship(
    "Child",
    uselist = False,
    primaryjoin=lambda: and_((Parent.id == Child.parent_id),(Child.type == "VR")),
    collection_class=ZepConnector("VR")
    )

但这引发了一个令人毛骨悚然的例外,谈到一个我不应该看到的领域,我不想看到。。。曾经。。。:-D

AttributeError: 'ZepConnector' object has no attribute '_sa_instance_state'

我使用的是Python2.4和SqlAlchemy 0.6.6,以防万一。在

如果有人有任何想法,指导,咨询。。。无论什么。。。我真的很感谢你和我分享。。。呃。。。我们。。。在

提前谢谢你!在

(如果你已经走到了这条线上,你当然应该得到一个“谢谢”,因为你耐心地阅读了这篇巨大的帖子)


Tags: infrompyimportselfchildzopehome
1条回答
网友
1楼 · 发布于 2024-06-02 18:38:13

明白了。在

我在sqlalchemygoogle小组也问过同样的问题,我得到了答案。在

http://groups.google.com/group/sqlalchemy/msg/5c8fc09a75fd4fa7

引用:

So this is incorrect - collection_class takes a class or other callable as an argument that will produce an instance of your collection. The ZepConnector source you have below indicates that ZepConnector("VR") is an instance of the collection. You need to use a lambda: there. The other errors you're getting would appear to extend from that (and is also why init is called on ZepConnector - you're calling it yourself).

感谢迈克尔·拜尔(以及所有试图帮助的人,即使阅读了这么一篇博文)

相关问题 更多 >