2009-12-11 21 views
10

Uygulamamda Twitter'da "follower" işlevlerini taklit etmesi gereken bir SQLAlchemy modelim var. Kullanıcıların birbirleriyle çok fazla ilişkisi vardır (hem takipçiler hem de takip edenler). İkincil tablo geri atıfta beriSQLAlchemy Tek Bir Tabloda Çoktan-Çok İlişki

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) 
    ) 

Ben, bu ilişkiyi oluşturmak için orm.mapper kullanmaya çalışıyor, ancak bir barikat biraz karşılaştık: tablolar aşağıdaki şekilde yapılandırılmıştır (sa sqlalchemy modülüdür) her iki yönde de aynı birincil tabloya. Bu ilişkiyi ORM ile nasıl eşleştireceğim?

cevap

6

Bu durumda açıkça primaryjoin ve secondaryjoin koşulları yazmak zorunda:

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), 
     ), 
    }, 
) 

Sana primaryjoin ve secondaryjoin parametrelerin ne anlama daha iyi anlamalarına yardımcı olmak için ayrıntılı Bu örnek yazdım. Elbette, backref ile sıralayıcı yapabilirsiniz.

BTW, aşağıdaki tabloda id sütununa ihtiyacınız yoktur, bunun yerine birleşik birincil anahtarı kullanın. Aslında, follower_id ve followee_id çiftinin benzersiz kısıtlamasını (birincil veya ek benzersiz anahtar olarak) tanımlamanız gerekir.

+0

Teşekkürler, bu mükemmel çalıştı. Aşağıdaki tablonun bir ID sütunu gerektirmediğini ve bir kompozit PK kullanabileceğini mi söylediniz? Bunun kullanıcı masasıyla nasıl çalışabileceğini anlamıyorum. – Travis

+0

Evet, bir hataydı. Tabloyu kastettim. –

+0

Bu işe girdim ve bunu deklaratif olarak yapmak zorundaydım, işte gelecekteki bulucular için eşdeğer. –

14

Ayrıca bunu bildirimli olarak da yapabilirsiniz.

Yukarıdaki kodlara dayanan benzer bir örnek, backref'i kullanıyorum.

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

Benim için, 'foreign_keys = [VolumeRelationship.c.VolumeID, VolumeRelationship.c.ParentID])' '' Volume.parents' '' ya analog olarak eklemek zorunda kaldım, aksi takdirde 'NoReferencedTableError' vardı. –