2011-09-14 15 views
33

Ho 3 tabelle: Utente, Comunità, membri di comunità (per relazione con molti utenti e comunità).SQLAlchemy ManyToMany tabella secondaria con campi aggiuntivi

creo questo tabelle utilizzando Flask-SQLAlchemy:

community_members = db.Table('community_members', 
       db.Column('user_id', db.Integer, db.ForeignKey('user.id')), 
       db.Column('community_id', db.Integer, db.ForeignKey('community.id')), 
       ) 


class Community(db.Model): 
    __tablename__ = 'community' 

    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(100), nullable=False, unique=True) 
    members = db.relationship(User, secondary=community_members, 
          backref=db.backref('community_members', lazy='dynamic')) 

ora voglio aggiungere ulteriore campo di community_members in questo modo:

community_members = db.Table('community_members', 
       db.Column('id', db.Integer, primary_key=True), 
       db.Column('user_id', db.Integer, db.ForeignKey('user.id')), 
       db.Column('community_id', db.Integer, db.ForeignKey('community.id')), 
       db.Column('time_create', db.DateTime, nullable=False, default=func.now()), 
       ) 

E ora in guscio pitone posso fare questo:

creare community:

> c = Community() 
> c.name = 'c1' 
> db.session.add(c) 
> db.session.commit() 

aggiungere membri a comunità:

> u1 = User.query.get(1) 
> u2 = User.query.get(2) 
> c.members.append(u1) 
> c.members.append(u2) 
> db.session.commit() 

> c.members 
[<User 1>, <User 2>] 

Ok, questo funziona.

Ma ora come posso ottenere time_create della tabella community_members?

risposta

46

Si dovrà passare dall'utilizzo di una relazione semplice, molti-a-molti all'utilizzo di un "oggetto associazione", che in pratica è solo prendere la tabella di associazione e assegnargli una mappatura di classe appropriata. Potrai quindi definire uno-a-molti rapporti a User e Community:

class Membership(db.Model): 
    __tablename__ = 'community_members' 

    id = db.Column('id', db.Integer, primary_key=True) 
    user_id = db.Column(db.Integer, db.ForeignKey('user.id')) 
    community_id = db.Column(db.Integer, db.ForeignKey('community.id')) 
    time_create = db.Column(db.DateTime, nullable=False, default=func.now()) 

    community = db.relationship(Community, backref="memberships") 
    user = db.relationship(User, backref="memberships") 


class Community(db.Model): 
    __tablename__ = 'community' 

    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(100), nullable=False, unique=True) 

Ma si può solo occasionalmente essere interessato al tempo creare; vuoi indietro la vecchia relazione! bene, non si desidera impostare il relationship due volte; perché sqlalchemy penserà che tu voglia in qualche modo due associazioni; che deve significare qualcosa di diverso! Si può fare questo con l'aggiunta in un association proxy.

from sqlalchemy.ext.associationproxy import association_proxy 

Community.members = association_proxy("memberships", "user") 
User.communities = association_proxy("memberships", "community") 
+6

Ho usato la soluzione e ha funzionato, ma ho ancora un problema. È possibile che Community.members (aggiunto con il proxy di associazione) restituisca un AppenderBaseQuery che possa aggiungere altri filtri, ad es. Community.members.filter_by (...)? Ero abituato a farlo con la semplice relazione molti-a-molti usando lazy = dynamic nella dichiarazione di relazione, ma dopo aver dato una mappatura di classe alla tabella di associazione sembra che non possa più farlo. – stefanobaldo

+0

Hai mai scoperto la soluzione @stefanobaldo - sarebbe davvero utile se lo facessi! – pip

0

Se avete solo bisogno di query community_members e community tavolo da un user_id noto (come user_id = 2), In SQLAlchemy, è possibile eseguire:

session.query(community_members.c.time_create, Community.name).filter(community_members.c.user_id==2)

per ottenere il risultato.

Problemi correlati