2009-12-11 5 views
10

Ich habe ein SQLAlchemy-Modell in meiner Anwendung eingerichtet, das die Funktionalität von "Follower" auf Twitter nachahmen sollte, dh. Benutzer haben eine Viele-zu-Viele-Beziehung (sowohl Follower als auch Follower). Die Tabellen sind wie folgt strukturiert (sa ist das sqlalchemy Modul):SQLAlchemy Viele-zu-viele Beziehungen auf einer einzigen Tabelle

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

Ich habe jedoch in ein bisschen eine gesperrte Straße und versuchte, diese Beziehung zu verwenden orm.mapper zu erstellen, da die Sekundärtabelle verweist in beide Richtungen zur gleichen primären Tabelle. Wie würde ich diese Beziehung zum ORM abbilden?

Antwort

6

Sie haben primaryjoin und secondaryjoin Bedingungen ausdrücklich in diesem Fall schreiben:

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

Ich habe diese Probe ausführliches schreiben Sie helfen, besser zu verstehen, was primaryjoin und secondaryjoin Parameter bedeuten. Sicher, Sie können es mit backref Sorter machen.

BTW, brauchen Sie nicht id Spalte in der folgenden Tabelle, verwenden Sie stattdessen Composite-Primärschlüssel. In der Tat sollten Sie die eindeutige Integritätsbedingung follower_id und followee_id sowieso definieren (entweder als primärer oder zusätzlicher eindeutiger Schlüssel).

+0

Danke, das hat perfekt funktioniert. Meinten Sie, dass die folgende Tabelle keine ID-Spalte benötigt und eine zusammengesetzte PK verwenden kann? Ich sehe nicht, wie das mit der Benutzertabelle funktionieren könnte. – Travis

+0

Ja, es war ein Fehler. Ich meinte folgenden Tisch. –

+0

Ich stieß darauf und musste es deklarativ tun, hier ist das Äquivalent für zukünftige Finder. –

14

Sie können dies auch deklarativ tun.

Hier ist ein ähnliches Beispiel basierend auf dem obigen Code, verwende ich die 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

Für mich musste ich analog von 'fremder_keys = [VolumeRelationship.c.VolumeID, VolumeRelationship.c.ParentID])' zu 'Volume.parents' hinzufügen, sonst hatte ich' NoReferencedTableError'. –

Verwandte Themen