2011-09-14 9 views
33

Mam 3 tabele: User, Community, community_members (dla relacji many2many użytkowników i społeczności).SQLAlchemy ManyToMany drugorzędny stół z dodatkowymi polami

tworzę to tabele przy użyciu skrzynkowego 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')) 

teraz chcę dodać dodatkowe pole do community_members tak:

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

A teraz w python shell mogę to zrobić:

utwórz społeczność:

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

dodać członków społeczności:

> 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, to działa.

Ale jak mogę teraz uzyskać time_create tabeli community_members?

Odpowiedz

46

Będziesz musiał zmienić zwykłą relację wiele do wielu na "Obiekt skojarzenia", który polega po prostu na przyjmowaniu tabeli powiązań i nadaniu jej właściwego odwzorowania klas. Będziesz wtedy zdefiniować jeden-do-wielu relacji do User i 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) 

Ale może być tylko sporadycznie zainteresowany czasu stworzenia; chcesz stary związek z powrotem! cóż, nie chcesz dwukrotnie konfigurować relationship; ponieważ sqlalchemy pomyśli, że w jakiś sposób chcesz dwa stowarzyszenia; co musi oznaczać coś innego! Można to zrobić poprzez dodanie w association proxy.

from sqlalchemy.ext.associationproxy import association_proxy 

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

Użyłem twojego rozwiązania i zadziałało, ale wciąż mam problem. Czy jest możliwe, że Community.members (dodane z proxy asocjacji) zwróci AppenderBaseQuery, że mogę dodać więcej filtrów, np. Community.members.filter_by (...)? Byłem przyzwyczajony do tego z prostą relacją wiele do wielu za pomocą lazy = dynamic w deklaracji relacji, ale po nadaniu mapowania klasy do tabeli powiązań wydaje się, że nie mogę tego więcej robić. – stefanobaldo

+0

Czy kiedykolwiek odkryłeś rozwiązanie @stefanobaldo - byłoby naprawdę pomocne, gdybyś tak zrobił! – pip

0

Jeśli trzeba tylko zapytać community_members i community stolika przez znanego user_id (takich jak user_id = 2), w SQLAlchemy, można wykonać:

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

, aby uzyskać wynik.

Powiązane problemy