简体   繁体   English

sqlalchemy中的多态自引用外键

[英]Polymorphic self referential foreign key in sqlalchemy

I am trying to resolve a problem with a self-referential table with Joined Table Inheritance where there is a foreign key linking the inheritance relationships, but then also a case where a class has an additional reference to an instance of its parent. 我正在尝试解决具有Joined Table Inheritance的自引用表的问题,该表中有一个外键链接继承关系,但是还有一种情况,其中类具有对其父实例的附加引用。 Best to go with a simplified example: 最好举一个简化的例子:

Class B inherits from Class A. Class B is linked to Class A by the id column through the Foreign Key in Class B. Class B also has a column ( a_id ) which references Class A which has nothing to do with the inheritance. B类继承自A类。B类通过B类中的外键通过id列链接到A类。B类还具有一个列( a_id ),该列引用与继承无关的A类。

from sqlalchemy import Column, Integer,ForeignKey, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship, backref

Base = declarative_base()


class A(Base):
    __tablename__ = 'a'
    satype = Column(String(50))
    __mapper_args__ = {
        'polymorphic_identity': 'a',
        'polymorphic_on': satype
    }

    id = Column(Integer, primary_key=True)


class B(A):
    __tablename__ = 'b'

    id = Column(Integer, ForeignKey('a.id'), primary_key=True)

    __mapper_args__ = {
        'polymorphic_identity': 'b'
    }

    a_id = Column(Integer, ForeignKey('a.id'))
    a = relationship('A', backref='b')

engine = create_engine('sqlite:///:memory:', echo=True)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()

As per the documentation , I would resolve the case where there are multiple ForeignKeys between tables by explicitly specifying in the relationship which was to be used. 根据文档 ,我将通过显式指定要使用的关系来解决表之间存在多个ForeignKey的情况。

class B(A):
    __tablename__ = 'b'

    id = Column(Integer, ForeignKey('a.id'), primary_key=True)

    __mapper_args__ = {
        'polymorphic_identity': 'b'
    }

    a_id = Column(Integer, ForeignKey('a.id'))
    # I know the primaryjoin is no longer needed in SA >= 0.8
    a = relationship('A', backref='b', foreign_keys=[a_id], primaryjoin=a_id==A.id)

I think the problem is that I don't seem to be able to figure out how to do the same for the polymorphic column id as I am not explicitly defining that relationship. 我认为问题在于我似乎无法弄清楚如何对多态列id执行相同的操作,因为我没有明确定义该关系。

Thanks to Michael Bayer in the SA google groups for this answer: 感谢SA Google组中的Michael Bayer给出以下答案:

The "mutually dependent foreign keys" document doesn't really apply to this case. “相互依赖的外键”文档实际上不适用于这种情况。 What happens here is that B(A) requires a join from B to A, and then Ba requires a different one. 这里发生的情况是B(A)需要从B连接到A,然后Ba需要一个不同的连接。 Even though the conventions here make it clear which foreign key constraint is which, the mapper still needs them to be explicitly spelled out, that's like this: 即使此处的约定清楚说明了哪个外键约束,映射器仍需要明确地阐明它们,就像这样:

class B(A):
    __tablename__ = 'b'

    id = Column(Integer, ForeignKey('a.id'), primary_key=True)

    __mapper_args__ = {
        'polymorphic_identity': 'b',
        'inherit_condition': id == A.id

    }

    a_id = Column(Integer, ForeignKey('a.id'))
    a = relationship(
        'A',
        backref='b', primaryjoin=A.id == a_id, remote_side=A.id)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM