SQLAlchemyのback_populatesとbackrefって何がどう違うの?っていうかどっちも書かないとどうなるの?という話。
結論から書くと、
(1)backrefを使用した場合
双方向のリレーションを自動的に組んでくれる。
(2)back_populatesを使用した場合
双方向のリレーションを自分で組む必要がある。
(3)back_populatesもbackrefも使用しない場合
トランザクション中、逆方向のフィールドが自動更新されない。
ということになる。
では、具体例を見ていく。
例としてEventモデルとTicketモデルを考える。
1つのEventは複数のTicketをもっている、One to Manyの関係。
backrefを使用した場合
class Event(Base):
__tablename__ = 'event'
id = Column(Integer, primary_key=True)
title = Column(String(255))
tickets = relationship("Ticket",backref="event")
class Ticket(Base):
__tablename__ = 'ticket'
id = Column(Integer,primary_key=True)
title = Column(String(255))
value = Column(Integer)
event_id = Column(Integer,ForeignKey('event.id'))
event = Event(title="test")
ticket = Ticket(title="test_ticket",value=5000)
event.tickets = [ticket]
event.tickets #Ticket Objects
ticket.event #Event Object
back_populatesを使用した場合
back_populatesを使用する場合は、双方向のリレーションを組まないと動作しない。
class Event(Base):
__tablename__ = 'event'
id = Column(Integer, primary_key=True)
title = Column(String(255))
tickets = relationship("Ticket",back_populates="event")
class Ticket(Base):
__tablename__ = 'ticket'
id = Column(Integer,primary_key=True)
title = Column(String(255))
value = Column(Integer)
event_id = Column(Integer,ForeignKey('event.id'))
event = relationship("Event",back_populates="tickets")
event = Event(title="test")
ticket = Ticket(title="test_ticket",value=5000)
event.tickets = [ticket]
event.tickets #Ticket Objects
ticket.event #Event Object
どちらも使用しない場合
class Event(Base):
__tablename__ = 'event'
id = Column(Integer, primary_key=True)
title = Column(String(255))
tickets = relationship("Ticket")
class Ticket(Base):
__tablename__ = 'ticket'
id = Column(Integer,primary_key=True)
title = Column(String(255))
value = Column(Integer)
event_id = Column(Integer,ForeignKey('event.id'))
event = relationship("Event")
event = Event(title="test")
ticket = Ticket(title="test_ticket",value=5000)
event.tickets = [ticket]
event.tickets #Ticket Objects
ticket.event #None
この場合、ticket→eventがNoneになっている。
つまり、トランザクション内ではticketにeventが紐付いていない事がわかる。
勿論、トランザクション終了後(eventオブジェクトをインサートした後)なら双方向で紐付いている。
event = self.session.query(Event).filter(Event.id==1).one()
ticket = self.session.query(Ticket).filter(Ticket.id==1).one()
event.tickets #Ticket Objects
ticket.event #Event Object