简体   繁体   English

使用SQLAlchemy具有多个自引用外键

[英]Using SQLAlchemy with multiple self-referential foreign keys

What if I had something like a double linked list in a relational database, for example: 如果我在关系数据库中有类似双链表的内容,例如:

node_id    left_id    right_id

1          null       2
2          1          3
3          2          null

Then I have some SQLAlchemy code like the following: 然后我有一些SQLAlchemy代码,如下所示:

class NodeClass(Base):
    __tablename__ = 'nodes_table'
    node_id = Column(Integer, primary_key=True)
    left_id = Column(Integer, ForeignKey('nodes_table.node_id'))
    right_id = Column(Integer, ForeignKey('nodes_table.node_id'))
    left = relationship('NodeClass') # Wrong
    right = relationship('NodeClass') # Wrong

If I have node_id 2, and I call NodeClass.left I would like to receive node_id 1 in return. 如果我有node_id 2,我调用NodeClass.left我想收到node_id 1作为回报。 How can I configure the SQLAlchemy relationships to behave this way? 如何配置SQLAlchemy关系以这种方式运行?

UPDATE: 更新:

I will give a second example. 我将举一个例子。 Consider a table of people, and each person has a mother and a father. 考虑一张人的表,每个人都有一个母亲和一个父亲。

person_id    mother_id    father_id

1            null         null
2            null         null
3            1            2

The SQLAlchemy code: SQLAlchemy代码:

class PersonClass(Base):
    __tablename__ = 'persons_table'
    person_id = Column(Integer, primary_key=True)
    mother_id = Column(Integer, ForeignKey('persons_table.person_id'))
    father_id = Column(Integer, ForeignKey('persons_table.person_id'))
    mother = relation('PersonClass') # Wrong
    father = relation('PersonClass') # Wrong

The code below shows how to configure the relationship: 下面的代码显示了如何配置关系:

class NodeClass(Base):
    __tablename__ = 'nodes_table'
    node_id = Column(Integer, primary_key=True)

    left_id = Column(Integer, ForeignKey('nodes_table.node_id'))
    left = relationship('NodeClass', remote_side=[node_id],
            primaryjoin=('NodeClass.left_id==NodeClass.node_id'),
            backref=backref("right", uselist=False),
            #lazy="joined", join_depth=9,
            )

But few things should be noted: 但是应该注意的事情很少:

  • only one end of the relationship is stored, the other is inferred. 只存储关系的一端,另一端被推断。 This might not be what you want, but it is much more simple to manage, and it is enough to set one side only myNode.left = myOtherNode and the other ( right ) will be set automatically (because of configured backref ) 这可能不是你想要的,但它管理起来要简单得多,只需设置一方myNode.left = myOtherNode就可以了,另一方( right )将自动设置(因为配置了backref
  • if both ends are stored ( right and left ), then 如果两端都存储( rightleft ),那么
    • both ends would need to be set in code and one has to ensure they are consistent, which might not be a trivial task 两端都需要在代码中设置,并且必须确保它们是一致的,这可能不是一项微不足道的任务
    • the insert of two nodes that are linked would require insert-1, insert-2, update-1 in case your primary key is computed on the database, as it is unknown during the first insert . 如果在数据库上计算主键,则链接的两个节点的插入将需要insert-1, insert-2, update-1 ,因为在第一次insert期间它是未知的。

UPDATE: Sample code to the UPDATE part of the question (but still using the original class name). 更新:问题的UPDATE部分的示例代码(但仍使用原始类名)。 One needs only to specify the primaryjoin and uselist=False : 人们只需要指定primaryjoinuselist=False

class NodeClass(Base):
    __tablename__ = 'nodes_table'
    node_id = Column(Integer, primary_key=True)

    left_id = Column(Integer, ForeignKey('nodes_table.node_id'))
    right_id = Column(Integer, ForeignKey('nodes_table.node_id'))

    left = relationship('NodeClass', primaryjoin = ('NodeClass.left_id == NodeClass.node_id'), use_list=False)
    right = relationship('NodeClass', primaryjoin = ('NodeClass.right_id == NodeClass.node_id'), use_list=False)

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

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