2011-09-14 23 views
33

Tengo 3 tablas: User, Community, community_members (para la relación many2many de usuarios y comunidad).SQLAlchemy Tabla secundaria ManyToMany con campos adicionales

puedo crear esta tablas usando matraz de 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')) 

ahora quiero añadir campos adicionales a community_members así:

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

Y ahora en Python Shell que pueda hacer esto:

create community:

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

agregar miembros a la comunidad:

> 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, esto funciona.

Pero, ¿cómo puedo obtener la tabla time_create of community_members?

Respuesta

46

Tendrá que pasar de utilizar una relación simple de varios a usar un "Objeto de asociación", que básicamente consiste en tomar la tabla de asociación y asignarle una asignación de clase adecuada. A continuación, defina uno-a-muchas relaciones a User y 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) 

Pero es posible que sólo ocasionalmente estar interesado en el momento de crear; quieres la antigua relación de vuelta! bueno, no quiere configurar el relationship dos veces; porque sqlalchemy pensará que de alguna manera quiere dos asociaciones; que debe significar algo diferente! Usted puede hacer esto mediante la adición de una association proxy.

from sqlalchemy.ext.associationproxy import association_proxy 

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

Utilicé su solución y funcionó, pero todavía tengo un problema. ¿Es posible que Community.members (agregado con el proxy de asociación) devuelva un AppenderBaseQuery para que pueda agregar más filtros, p. Community.members.filter_by (...)? Estaba acostumbrado a hacer eso con la relación simple de varios a muchos usando lazy = dynamic en la declaración de relación, pero después de dar un mapeo de clase a la tabla de asociación parece que ya no puedo hacerlo. – stefanobaldo

+0

¿Alguna vez descubrió la solución @stefanobaldo? ¡Sería realmente útil si lo hiciera! – pip

0

Si sólo necesita consulta community_members y community mesa por un user_id conocido (como user_id = 2), En SQLAlchemy, puede realizar:

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

para obtener el resultado.

Cuestiones relacionadas