Sqlalchemy 邻接列表+;关系中使用的抽象基类继承

Sqlalchemy 邻接列表+;关系中使用的抽象基类继承,sqlalchemy,Sqlalchemy,下面是邻接列表+继承的示例。这与预期一样有效,但如果我尝试在另一个模型Mammut中使用它作为关系,它会引发以下错误: Traceback (most recent call last): File "bin/py", line 73, in <module> exec(compile(__file__f.read(), __file__, "exec")) File "../adjacency_list.py", line 206, in <module>

下面是邻接列表+继承的示例。这与预期一样有效,但如果我尝试在另一个模型
Mammut
中使用它作为关系,它会引发以下错误:

Traceback (most recent call last):
  File "bin/py", line 73, in <module>
    exec(compile(__file__f.read(), __file__, "exec"))
  File "../adjacency_list.py", line 206, in <module>
    create_entries(IntTreeNode)
  File "../adjacency_list.py", line 170, in create_entries
    mut.nodes.append(node)
  File "/home/xxx/.buildout/eggs/SQLAlchemy-0.9.8-py3.4-linux-x86_64.egg/sqlalchemy/orm/dynamic.py", line 304, in append
    attributes.instance_dict(self.instance), item, None)
  File "/home/xxx/.buildout/eggs/SQLAlchemy-0.9.8-py3.4-linux-x86_64.egg/sqlalchemy/orm/dynamic.py", line 202, in append
    self.fire_append_event(state, dict_, value, initiator)
  File "/home/xxx/.buildout/eggs/SQLAlchemy-0.9.8-py3.4-linux-x86_64.egg/sqlalchemy/orm/dynamic.py", line 99, in fire_append_event
    value = fn(state, value, initiator or self._append_token)
  File "/home/xxx/.buildout/eggs/SQLAlchemy-0.9.8-py3.4-linux-x86_64.egg/sqlalchemy/orm/attributes.py", line 1164, in emit_backref_from_collection_append_event
    child_impl.append(
AttributeError: '_ProxyImpl' object has no attribute 'append'

具体继承可能非常困难,AbstractConcreteBase本身在0.9中有缺陷,这些缺陷阻碍了像这样的复杂映射的使用

使用1.0(未发布,请使用git master),我可以获得如下主要元素:

from sqlalchemy import Column, String, Integer, create_engine, ForeignKey, Float
from sqlalchemy.orm import Session, relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.ext.declarative import declared_attr, AbstractConcreteBase


Base = declarative_base()


class Mammut(Base):
    __tablename__ = "mammut"

    id = Column(Integer, primary_key=True)
    nodes = relationship(
        'TreeNode',
        lazy='dynamic',
        back_populates='mammut',
    )


class TreeNode(AbstractConcreteBase, Base):
    id = Column(Integer, primary_key=True)
    name = Column(String)

    @declared_attr
    def __tablename__(cls):
        if cls.__name__ == 'TreeNode':
            return None
        else:
            return cls.__name__.lower()

    @declared_attr
    def __mapper_args__(cls):
        return {'polymorphic_identity': cls.__name__, 'concrete': True}

    @declared_attr
    def parent_id(cls):
        return Column(Integer, ForeignKey(cls.id))

    @declared_attr
    def mammut_id(cls):
        return Column(Integer, ForeignKey('mammut.id'))

    @declared_attr
    def mammut(cls):
        return relationship("Mammut", back_populates="nodes")

    @declared_attr
    def children(cls):
        return relationship(
            cls,
            back_populates="parent",
            collection_class=attribute_mapped_collection('name'),
        )

    @declared_attr
    def parent(cls):
        return relationship(
            cls, remote_side="%s.id" % cls.__name__,
            back_populates='children')


class IntTreeNode(TreeNode):
    value = Column(Integer)


class FloatTreeNode(TreeNode):
    value = Column(Float)
    miau = Column(String(50), default='zuff')

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

session = Session(e)

root = IntTreeNode(name='root')
IntTreeNode(name='n1', parent=root)
n2 = IntTreeNode(name='n2', parent=root)
IntTreeNode(name='n2n1', parent=n2)

m1 = Mammut()
m1.nodes.append(n2)
m1.nodes.append(root)

session.add(root)
session.commit()


session.close()

root = session.query(TreeNode).filter_by(name='root').one()
print root.children