2010-10-21 4 views
5

Lo siento si la nomenclatura preferida no es la inversa, lo que puede haber dificultado mi búsqueda. En cualquier caso, estoy tratando con dos clases declarativas de sqlalchemy, que es una relación de muchos a muchos. El primero es Cuenta, y el segundo es Colección. Los usuarios "compran" colecciones, pero quiero mostrar las primeras 10 colecciones que el usuario no ha comprado.sqlalchemy many-to-many, pero inverso?

from sqlalchemy import * 
from sqlalchemy.orm import scoped_session, sessionmaker, relation 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

engine = create_engine('sqlite:///:memory:', echo=True) 
Session = sessionmaker(bind=engine) 

account_to_collection_map = Table('account_to_collection_map', Base.metadata, 
           Column('account_id', Integer, ForeignKey('account.id')), 
           Column('collection_id', Integer, ForeignKey('collection.id'))) 

class Account(Base): 
    __tablename__ = 'account' 

    id = Column(Integer, primary_key=True) 
    email = Column(String) 

    collections = relation("Collection", secondary=account_to_collection_map) 

    # use only for querying? 
    dyn_coll = relation("Collection", secondary=account_to_collection_map, lazy='dynamic') 

    def __init__(self, email): 
     self.email = email 

    def __repr__(self): 
     return "<Acc(id=%s email=%s)>" % (self.id, self.email) 

class Collection(Base): 
    __tablename__ = 'collection' 

    id = Column(Integer, primary_key=True) 
    slug = Column(String) 

    def __init__(self, slug): 
     self.slug = slug 

    def __repr__(self): 
     return "<Coll(id=%s slug=%s)>" % (self.id, self.slug) 

Así, con account.collections, puedo conseguir todas las colecciones, y con dyn_coll.limit (1) .all() Puedo solicitar consultas a la lista de colecciones ... pero ¿cómo puedo hacer lo ¿inverso? Me gustaría obtener las primeras 10 colecciones que la cuenta tiene no han mapeado.

Cualquier ayuda es increíblemente apreciada. ¡Gracias!

Respuesta

5

No utilizaría la relación para este propósito, ya que técnicamente no es una relación que está construyendo (por lo que todos los trucos de mantenerla sincronizada en ambos lados, etc. no funcionarían).
OMI, la manera más limpia sería definir una consulta sencilla que le devuelva los objetos que está buscando:

class Account(Base): 
    ... 
    # please note added *backref*, which is needed to build the 
    #query in Account.get_other_collections(...) 
    collections = relation("Collection", secondary=account_to_collection_map, backref="accounts") 

    def get_other_collections(self, maxrows=None): 
     """ Returns the collections this Account does not have yet. """ 
     q = Session.object_session(self).query(Collection) 
     q = q.filter(~Collection.accounts.any(id=self.id)) 
     # note: you might also want to order the results 
     return q[:maxrows] if maxrows else q.all() 
... 
+0

Huh. Obviamente tengo mucho que aprender sobre sqlalchemy. :) ¡Gracias! – Hoopes