2012-01-21 156 views
4

我想建立另一個許多一對多關係的關係,代碼如下所示:SQLAlchemy的關係,許多一對多關聯表

from sqlalchemy import Column, Integer, ForeignKey, Table, ForeignKeyConstraint, create_engine 
from sqlalchemy.orm import relationship, backref, scoped_session, sessionmaker 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base() 

supervision_association_table = Table('supervision', Base.metadata, 
    Column('supervisor_id', Integer, ForeignKey('supervisor.id'), primary_key=True), 
    Column('client_id', Integer, ForeignKey('client.id'), primary_key=True) 
) 

class User(Base): 
    __tablename__ = 'user' 

    id = Column(Integer, primary_key=True) 

class Supervisor(User): 
    __tablename__ = 'supervisor' 
    __mapper_args__ = {'polymorphic_identity': 'supervisor'} 

    id = Column(Integer, ForeignKey('user.id'), primary_key = True) 

    schedules = relationship("Schedule", backref='supervisor') 

class Client(User): 
    __tablename__ = 'client' 
    __mapper_args__ = {'polymorphic_identity': 'client'} 

    id = Column(Integer, ForeignKey('user.id'), primary_key = True) 

    supervisor = relationship("Supervisor", secondary=supervision_association_table, 
           backref='clients') 
    schedules = relationship("Schedule", backref="client") 

class Schedule(Base): 
    __tablename__ = 'schedule' 
    __table_args__ = (
     ForeignKeyConstraint(['client_id', 'supervisor_id'], ['supervision.client_id', 'supervision.supervisor_id']), 
    ) 

    id = Column(Integer, primary_key=True) 
    client_id = Column(Integer, nullable=False) 
    supervisor_id = Column(Integer, nullable=False) 

engine = create_engine('sqlite:///temp.db') 
db_session = scoped_session(sessionmaker(bind=engine)) 
Base.metadata.create_all(bind=engine) 

我想要做的是有關一個特定的客戶 - 主管關係的時間表,但我還沒有發現如何去做。通過SQLAlchemy文檔,我發現了一些提示,導致Schedule-Table上的ForeignKeyConstraint。

如何指定關係以使此關聯有效?

+0

什麼是具有獨立supervision_association_table,然後有一個一對一的關係給它的時間表類的目的是什麼?爲什麼不使用一個表,然後使用關聯對象模式? http://www.sqlalchemy.org/docs/orm/relationships.html#association-object。在任何情況下,如果您保留兩個獨立的「時間表」和「監督」表,您需要在這裏映射supervision_associaiton_table以創建一系列關係鏈,然後再與相關項目建立關係鏈。 – zzzeek

+1

客戶真的可以有超過1個主管?您的M-N表格建議*是*,但關係(主管)的名稱意味着*否*。 – van

+0

@zzzeek我希望課程表類與監督有一對多的關係,這樣一對客戶主管可以有許多不同的時間表。 – dasmaze

回答

7

您需要映射supervision_association_table,以便您可以創建與其之間的關係。

我可能會在這裏誇耀一些東西,但它似乎是因爲你有多對多在這裏你真的不能有Client.schedules - 如果我說Client.schedules.append(some_schedule),哪一行在「監督」是指向?所以下面的例子爲那些加入每個SupervisorAssociation的Schedule集合的人提供了一個只讀的「彙總」訪問器。當方便時,association_proxy擴展用於隱藏SupervisionAssociation對象的細節。

from sqlalchemy import Column, Integer, ForeignKey, Table, ForeignKeyConstraint, create_engine 
from sqlalchemy.orm import relationship, backref, scoped_session, sessionmaker 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.ext.associationproxy import association_proxy 
from itertools import chain 

Base = declarative_base() 

class SupervisionAssociation(Base): 
    __tablename__ = 'supervision' 

    supervisor_id = Column(Integer, ForeignKey('supervisor.id'), primary_key=True) 
    client_id = Column(Integer, ForeignKey('client.id'), primary_key=True) 

    supervisor = relationship("Supervisor", backref="client_associations") 
    client = relationship("Client", backref="supervisor_associations") 
    schedules = relationship("Schedule") 

class User(Base): 
    __tablename__ = 'user' 

    id = Column(Integer, primary_key=True) 

class Supervisor(User): 
    __tablename__ = 'supervisor' 
    __mapper_args__ = {'polymorphic_identity': 'supervisor'} 

    id = Column(Integer, ForeignKey('user.id'), primary_key = True) 

    clients = association_proxy("client_associations", "client", 
         creator=lambda c: SupervisionAssociation(client=c)) 

    @property 
    def schedules(self): 
     return list(chain(*[c.schedules for c in self.client_associations])) 

class Client(User): 
    __tablename__ = 'client' 
    __mapper_args__ = {'polymorphic_identity': 'client'} 

    id = Column(Integer, ForeignKey('user.id'), primary_key = True) 

    supervisors = association_proxy("supervisor_associations", "supervisor", 
         creator=lambda s: SupervisionAssociation(supervisor=s)) 
    @property 
    def schedules(self): 
     return list(chain(*[s.schedules for s in self.supervisor_associations])) 

class Schedule(Base): 
    __tablename__ = 'schedule' 
    __table_args__ = (
     ForeignKeyConstraint(['client_id', 'supervisor_id'], 
     ['supervision.client_id', 'supervision.supervisor_id']), 
    ) 

    id = Column(Integer, primary_key=True) 
    client_id = Column(Integer, nullable=False) 
    supervisor_id = Column(Integer, nullable=False) 
    client = association_proxy("supervisor_association", "client") 

engine = create_engine('sqlite:///temp.db', echo=True) 
db_session = scoped_session(sessionmaker(bind=engine)) 
Base.metadata.create_all(bind=engine) 

c1, c2 = Client(), Client() 
sp1, sp2 = Supervisor(), Supervisor() 
sch1, sch2, sch3 = Schedule(), Schedule(), Schedule() 

sp1.clients = [c1] 
c2.supervisors = [sp2] 
c2.supervisor_associations[0].schedules = [sch1, sch2] 
c1.supervisor_associations[0].schedules = [sch3] 

db_session.add_all([c1, c2, sp1, sp2, ]) 
db_session.commit() 


print c1.schedules 
print sp2.schedules 
+0

這基本上就是我所說的,在關聯表上有時間表並將它與一個類進行映射。我沒有使用關聯代理,儘管我可能會這樣做。這次真是萬分感謝。 – dasmaze