はるみちゃんのてっくぶろぐ

はるみちゃんのブログだよ。主に技術系の記事を書くよ。

SQLAlchemyのback_populatesとbackref

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