2014-02-10 2 views
5

상황 :많은 - 투 - 많은 SQLAlchemy의 채우기 관계 ID의 대신 객체를 사용

그래서, 내가 association table를 사용하여 SQLAlchemy의에서 기본 대다 관계를 가지고있다.
예를 들어, 사람이 많은 파티에 참석할 수 있으며, 파티 손님들 많은 사람이 있습니다 : 나는, 나는 이런 식으로 뭔가를 할 것 파티에 손님의 목록을 추가하고자한다면 일반적으로

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')) 
) 

를 : 왕자, 올리비아와 브리트니 모든 <Person> 인스턴스이며, my_party가 <SexyParty> 인스턴스

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

....

내 질문 :

나는 사람 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