在sqlalchemy中,当子表有多个外键到父表时,如何使用多态连接表继承?

时间:2013-02-14 22:14:39

标签: python inheritance orm sqlalchemy polymorphism

我有一个名为pbx_point的父表,其中包含point_type列。我还有一个名为pbx_route的子表,其中一个名为point_id的列指向pbx_point

我想使用sqlalchemy的连接表继承通过声明性基础关联这两个表,并使用多态继承

这样可以正常工作 - 或者更确切地说,如果不是因为以下附加约束:pbx_point还有一个名为initial_route_id的外键指向pbx_route

我也在使用下面的反射,但db就像我上面所描述的那样。我得到的错误是sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between 'pbx_point' and 'pbx_route'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly.

这是有道理的,因为“幕后”的decarative base是在两个映射类上创建一个relationship()属性。我希望选择pbx_route.point_id作为parent_id链接,但它也会看到pbx_point.initial_route_id列。如果我正在创建这种关系(),这很容易修复,但我不是 - 声明性继承系统是。

我可以传递给__mapper_args__的其他参数,例如polymorphic_parent_col,这会让我指定我想要的外键吗?如果没有,我该如何解决这个问题?

感谢。

class MyBase(DeferredReflection):
    @declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

Base = declarative_base(cls=MyBase)

class pbx_point(Base):
    __mapper_args__ = dict(
        polymorphic_on='point_type',
        with_polymorphic='*',
    )

class pbx_route(pbx_point):
    __mapper_args__ = dict(polymorphic_identity='pbx.route')

这是我得到的堆栈跟踪:

Traceback (most recent call last):
  File "db.py", line 50, in <module>
    Base.prepare(engine)
  File "env/local/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py", line 431, in prepare
    thingy.map()
  File "env/local/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 379, in map
    **mapper_args
  File "env/local/lib/python2.7/site-packages/sqlalchemy/orm/__init__.py", line 1147, in mapper
    return Mapper(class_, local_table, *args, **params)
  File "env/local/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 213, in __init__
    self._configure_inheritance()
  File "env/local/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 517, in _configure_inheritance
    self.local_table)
  File "env/local/lib/python2.7/site-packages/sqlalchemy/sql/util.py", line 397, in join_condition
    "join explicitly." % (a.description, b.description))
sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between 'pbx_point' and 'pbx_route'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly.

这表明它在https://bitbucket.org/sqlalchemy/sqlalchemy/src/7f3494ebad58/lib/sqlalchemy/orm/mapper.py?at=default#cl-517死亡。上面的几行代表了映射器kwarg inherit_condition,这似乎是我需要的。

1 个答案:

答案 0 :(得分:11)

关键是映射器的inherit_condition参数。多态信息实际上与此步骤无关。

更正模型:

class MyBase(DeferredReflection):
    @declared_attr
    def __tablename__(cls):
        return cls.__name__.lower()

Base = declarative_base(cls=MyBase)

class pbx_point(Base):
    __mapper_args__ = dict(
        polymorphic_on='point_type',
        with_polymorphic='*',
    )
    id = Column(Integer, primary_key=True)

class pbx_route(pbx_point):
    point_id = Column(Integer, ForeignKey(pbx_point.id))
    __mapper_args__ = dict(
        polymorphic_identity='pbx.route',
        inherit_condition=(point_id == pbx_point.id)
    )

我需要添加idpoint_id列,以便在inherit_condition参数中使用它们。只有使用反射才有可能做到这一点,但这不是一个可怕的障碍。