2014-02-10 51 views
5

情況:使用的ID,而不是對象填充一個SQLAlchemy的許多一對多的關係

所以,我在SQLAlchemy中使用association table一個基本的許多一對多的關係。
例如,一個人可以參加許多政黨和政黨可以有許多的人作爲嘉賓:

class Person(Base): 
    __tablename__ = 'person' 
    id  = Column(Integer, primary_key=True) 
    name = db.Column(db.String(50)) 


class SexyParty(Base): 
    __tablename__ = 'sexy_party' 
    id  = Column(Integer, primary_key=True) 
    guests = relationship('Person', secondary='guest_association', 
         lazy='dynamic', backref='parties') 

guest_association = Table(
    'guest_association', 
    Column('user_id',  Integer(), ForeignKey('person.id')), 
    Column('sexyparty.id', Integer(), ForeignKey('sexyparty.id')) 
) 

通常情況下,如果我想的客人列表中添加一個派對,我會做這樣的事情:

my_guests = [prince, olivia, brittany, me] 
my_party.guests = guests 
db.session.commit() 

...這裏的王子,奧利維亞和布列塔尼都是<Person>實例,my_party是<SexyParty>實例。

我的問題

我想客人添加到使用人的ID,而不是實例的一方。 例如:

guest_ids = [1, 2, 3, 5] 
my_party.guests = guest_ids # <-- This fails, because guest_ids 
          # are not <Person> instances 

我總是可以從數據庫加載實例,但這將帶來不必要的DB查詢只是設置一個簡單的許多一對多的關係。

我該如何去設置使用person_id列表的.guests屬性? 必須有一個簡單的方法來做到這一點,因爲關聯表最終代表使用ID的多對多關係...

在此先感謝,希望問題是清楚的。

回答

8
from sqlalchemy import * 
from sqlalchemy.orm import * 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

class Person(Base): 
    __tablename__ = 'person' 
    id  = Column(Integer, primary_key=True) 
    name = Column(String(50)) 


class SexyParty(Base): 
    __tablename__ = 'sexy_party' 
    id  = Column(Integer, primary_key=True) 
    guests = relationship('Person', secondary='guest_association', 
         lazy='dynamic', backref='parties') 

guest_association = Table(
    'guest_association', Base.metadata, 
    Column('user_id',  Integer(), ForeignKey('person.id'), primary_key=True), 
    Column('sexyparty_id', Integer(), ForeignKey('sexy_party.id'), primary_key=True) 
) 


e = create_engine("sqlite://", echo=True) 
Base.metadata.create_all(e) 

sess = Session(e) 

p1 = Person(id=1, name='p1') 
p2 = Person(id=2, name='p2') 
p3 = Person(id=3, name='p3') 
p4 = Person(id=4, name='p4') 

sp1 = SexyParty(id=1) 

sess.add_all([sp1, p1, p2, p3, p4]) 
sess.commit() 

# method one. use insert() 
sess.execute(guest_association.insert().values([(1, 1), (2, 1)])) 

# method two. map, optional association proxy 
from sqlalchemy.ext.associationproxy import association_proxy 

class GuestAssociation(Base): 
    __table__ = guest_association 
    party = relationship("SexyParty", backref="association_recs") 

SexyParty.association_ids = association_proxy(
        "association_recs", "user_id", 
        creator=lambda uid: GuestAssociation(user_id=uid)) 

sp1.association_ids.extend([3, 4]) 
sess.commit() 
+0

完美答案。令人印象深刻! – tohster