【问题标题】:SQLAlchemy Many-to-Many Relationship on a Single Table单个表上的 SQLAlchemy 多对多关系
【发布时间】:2010-12-25 17:53:08
【问题描述】:

我在我的应用程序中设置了一个 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)
    )

但是,我在尝试使用 orm.mapper 来创建这种关系时遇到了一些障碍,因为辅助表在两个方向上都引用同一个主表。我将如何将此关系映射到 ORM?

【问题讨论】:

    标签: python orm sqlalchemy


    【解决方案1】:

    在这种情况下,您必须明确编写 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),
            ),
        },
    )
    

    我编写了这个详细示例,以帮助您更好地理解 primaryjoinsecondaryjoin 参数的含义。当然,您可以使用backref 对其进行分类。

    顺便说一句,您不需要下表中的id 列,而是使用复合主键。实际上,无论如何,您都应该定义 follower_idfollowee_id 对的唯一约束(作为主键或附加唯一键)。

    【讨论】:

    • 谢谢,这很好用。您的意思是下表不需要 ID 列并且可以使用复合 PK 吗?我不明白这如何与 users 表一起使用。
    • 是的,这是一个错误。我的意思是如下表。
    • 我遇到了这个问题,必须以声明的方式进行,这是未来发现者的等价物。
    • @DenisOtkidach 你能简单说明一下辅助连接和主连接的作用吗?
    • 正如@Zion 所说,将有助于详细说明主连接和辅助连接。但是这里是文档:docs.sqlalchemy.org/en/latest/orm/…
    【解决方案2】:

    您也可以以声明方式执行此操作。

    这是基于上述代码的类似示例,我确实使用了 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")
    

    【讨论】:

    • 对我来说,我必须将foreign_keys = [VolumeRelationship.c.VolumeID, VolumeRelationship.c.ParentID]) 的类似物添加到Volume.parents,否则我有NoReferencedTableError
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    相关资源
    最近更新 更多