2009-12-11 72 views
10

我在我的应用程序中设置了一个SQLAlchemy模型,该模型应该模仿Twitter上的“追随者”功能,即。用户与对方(追随者和追随者)有着多对多的关系。该表的结构如下(sa是SQLAlchemy的模块):SQLAlchemy单表上的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?

回答

6

你必须明确地写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(无论是主要还是附加的唯一键)。

+0

谢谢,这工作完美。你的意思是下面的表不需要ID列,可以使用复合PK?我不明白这是如何与用户表一起工作的。 – Travis 2009-12-11 19:29:26

+0

是的,这是一个错误。我的意思是遵循表格。 – 2009-12-11 20:27:37

+0

我遇到过这个问题,不得不以声明方式来做,这是未来发现者的等价物。 – 2011-04-13 16:00:20

14

你也可以用声明来做到这一点。

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

对我来说,我不得不添加模拟 'foreign_keys = [VolumeRelationship.c.VolumeID, VolumeRelationship.c.ParentID])''Volume.parents',否则我有'NoReferencedTableError'。 – 2014-06-08 15:45:44