【问题标题】:Self-referencing many-to-many relationship with an association object in SQLAlchemy与 SQLAlchemy 中的关联对象的自引用多对多关系
【发布时间】:2021-05-31 02:42:50
【问题描述】:

我找到了与关联表建立自引用多对多关系的示例。如何使用关联对象实现同样的效果?

以下代码基于:How can I achieve a self-referencing many-to-many relationship on the SQLAlchemy ORM back referencing to the same attribute?

from sqlalchemy import Table, Column, Integer, ForeignKey
from db.common import Base
from sqlalchemy.orm import relationship

M2M = Table('m2m',
            Base.metadata,
            Column('entity_parent_id', 
                   Integer,
                   ForeignKey('entity.id'),
                   primary_key=True),
            Column('entity_child_id',
                   Integer,
                   ForeignKey('entity.id'), 
                   primary_key=True),
)


class Entity(Base):
    __tablename__ = 'entity'

    id = Column(Integer, primary_key=True)

    entity_childs = relationship("Entity",
                                    secondary=M2M,
                                    primaryjoin="Enity.id==m2m.c.entity_parent_id",
                                    secondaryjoin="Enity.id==m2m.c.entity_child_id",
                                    )

    entity_parents = relationship("Entity",
                                     secondary=M2M,
                                     primaryjoin="Enity.id==m2m.c.entity_child_id",
                                     secondaryjoin="Enity.id==m2m.c.entity_parent_id",
                                     )

【问题讨论】:

    标签: python sqlalchemy many-to-many self-referencing-table


    【解决方案1】:

    以下方法使用关联对象而不是关联表来获得自引用的多对多关系:

    from sqlalchemy import Column, Integer, ForeignKey, create_engine, String
    from sqlalchemy.orm import relationship, sessionmaker
    from sqlalchemy.ext.declarative import declarative_base
    
    Base = declarative_base()
    
    class EntityAssociation(Base):
        __tablename__ = 'entity_association'
    
        entity_parent_id = Column(Integer, ForeignKey('entity.id'), primary_key=True)
        entity_child_id = Column(Integer, ForeignKey('entity.id'), primary_key=True)
    
    class Entity(Base):
        __tablename__ = 'entity'
    
        id = Column(Integer, primary_key=True)
        name = Column(String)
    
        entity_childs = relationship('Entity',
                                     secondary='entity_association',
                                     primaryjoin=id==EntityAssociation.entity_parent_id,
                                     secondaryjoin=id==EntityAssociation.entity_child_id,
                                     backref='childs')
    
        entity_parents = relationship('Entity',
                                      secondary='entity_association',
                                      primaryjoin=id==EntityAssociation.entity_child_id,
                                      secondaryjoin=id==EntityAssociation.entity_parent_id,
                                      backref='parents')
    
        def __repr__(self):
            return f'<Entity(name={self.name})>'
    
    if __name__ == '__main__':
        engine = create_engine('sqlite://')
        Base.metadata.create_all(engine)
        Session = sessionmaker(engine)
    
        db = Session()
    
        parent1 = Entity(name='parent1')
        parent2 = Entity(name='parent2')
        child1 = Entity(name='child1')
        child2 = Entity(name='child2')
    
        parent1.entity_childs = [child1, child2]
        parent2.entity_childs = [child2]
    
        db.add(parent1)
        db.add(parent2)
        db.add(child1)
        db.add(child2)
        db.commit()
    
        entities = db.query(Entity).all()
        for entity in entities:
            print(entity)
            print('   Parent: ', entity.entity_parents)
            print('   Childs: ', entity.entity_childs)
            print()
    

    这将产生以下结果:

    <Entity(name=parent1)>
       Parent:  []
       Childs:  [<Entity(name=child1)>, <Entity(name=child2)>]
    
    <Entity(name=child1)>
       Parent:  [<Entity(name=parent1)>]
       Childs:  []
    
    <Entity(name=child2)>
       Parent:  [<Entity(name=parent1)>, <Entity(name=parent2)>]
       Childs:  []
    
    <Entity(name=parent2)>
       Parent:  []
       Childs:  [<Entity(name=child2)>]
    

    【讨论】:

    • 你好 rfkortekass。非常感谢您的回答和对我问题的编辑。它工作正常。我的问题是让primaryjoin和secondaryjoin以正确的方式。我想我必须弄清楚,joinobject到底是什么。
    猜你喜欢
    • 2018-11-24
    • 2015-03-16
    • 1970-01-01
    • 2011-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-02
    相关资源
    最近更新 更多