SQLAlchemy单表上的多对多关系

Tra*_*vis 13 python orm sqlalchemy

我在我的应用程序中设置了一个SQLAlchemy模型,它应该模仿Twitter上"关注者"的功能,即.用户与彼此之间存在多对多关系(关注者和关注者).这些表的结构如下(sa是sqlalchemy模块):

t_users = sa.Table("users", meta.metadata,
    sa.Column("id", sa.types.Integer, primary_key=True),
    sa.Column("email", sa.types.String(320), unique=True, nullable=False),
    ...etc...
    )

t_follows = sa.Table("follows", meta.metadata,
    sa.Column("id", sa.types.Integer, primary_key=True),
    sa.Column("follower_id", sa.types.Integer, sa.ForeignKey('users.id'), nullable=False),
    sa.Column("followee_id", sa.types.Integer, sa.ForeignKey('users.id'), nullable=False)
    )
Run Code Online (Sandbox Code Playgroud)

我碰到了一下但是一个路障,试图用orm.mapper建立这种关系,因为辅助表是指回同一个主表在两个方向.我如何将这种关系映射到ORM?

Kur*_*lep 21

您也可以声明性地执行此操作.

这是一个基于上面代码的类似示例,我使用backref.

VolumeRelationship = Table(
    'VolumeRelationship', Base.metadata,
    Column('ParentID', Integer, ForeignKey('Volumes.ID')),
    Column('VolumeID', Integer, ForeignKey('Volumes.ID'))
    )

class Volume(Base):
    """ Volume Object """
    __tablename__ = "Volumes"

    id = Column('ID', Integer, primary_key=True, nullable=False)
    type = Column('Type', String(25))
    name = Column('Name', String(25))
    poolid = Column('pool', Integer, ForeignKey('Pools.ID'))
    parents = relation(
                    'Volume',secondary=VolumeRelationship,
                    primaryjoin=VolumeRelationship.c.VolumeID==id,
                    secondaryjoin=VolumeRelationship.c.ParentID==id,
                    backref="children")
Run Code Online (Sandbox Code Playgroud)

  • 对我来说,我必须将 `foreign_keys = [VolumeRelationship.c.VolumeID, VolumeRelationship.c.ParentID])` 的类似物添加到 `Volume.parents`,否则我有 `NoReferencedTableError`。 (3认同)

Den*_*ach 7

在这种情况下,您必须明确地编写primaryjoinsecondaryjoin条件:

mapper(
    User, t_users,
    properties={
        'followers': relation(
            User,
            secondary=t_follows,
            primaryjoin=(t_follows.c.followee_id==t_users.c.id),
            secondaryjoin=(t_follows.c.follower_id==t_users.c.id),
        ),
        'followees': relation(
            User,
            secondary=t_follows,
            primaryjoin=(t_follows.c.follower_id==t_users.c.id),
            secondaryjoin=(t_follows.c.followee_id==t_users.c.id),
        ),
    },
)
Run Code Online (Sandbox Code Playgroud)

我写了这个示例详细信息,以帮助您更好地理解什么primaryjoinsecondaryjoin参数的意思.当然,你可以用它进行分拣backref.

顺便说一句,你不需要id下表中的列,而是使用复合主键.实际上,您应该定义唯一约束follower_idfollowee_id对,无论是作为主键还是其他唯一键.