SQLAlchemy에서 back_populates 사용 시점
SQLAlchemy에서 back_populates 사용 시점
back_populates를 사용해야 하는 경우는 다음과 같습니다.
양방향 관계를 정의할 때
두 모델 간에 양방향 관계를 정의하려면 relationship 함수에 back_populates 매개변수를 사용해야 합니다. 예를 들어, Parent
모델과 Child
모델 간에 양방향 관계를 정의하려면 다음과 같이 코드를 작성합니다.
class Parent(Base):
__tablename__ = "parent_table"
id = Column(Integer, primary_key=True)
children = relationship("Child", back_populates="parent")
class Child(Base):
__tablename__ = "child_table"
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("parent_table.id"))
parent = relationship("Parent", back_populates="children")
관계의 이름을 명시적으로 지정할 때
relationship 함수의 첫 번째 매개변수는 관계의 이름을 지정하는 데 사용됩니다. 만약 두 모델에서 서로 다른 이름으로 관계를 참조하고 싶다면 back_populates 매개변수를 사용해야 합니다. 예를 들어, Parent
모델에서 children
이라는 이름으로 관계를 참조하고, Child
모델에서 parent
라는 이름으로 관계를 참조하고 싶다면 다음과 같이 코드를 작성합니다.
class Parent(Base):
__tablename__ = "parent_table"
id = Column(Integer, primary_key=True)
children = relationship("Child", back_populates="my_parent")
class Child(Base):
__tablename__ = "child_table"
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("parent_table.id"))
my_parent = relationship("Parent", back_populates="children")
관계의 속성을 사용자 정의할 때
relationship 함수의 properties 매개변수를 사용하여 관계의 속성을 사용자 정의할 수 있습니다. 만약 관계의 속성을 사용자 정의하고 싶다면 back_populates 매개변수를 사용해야 합니다. 예를 들어, Parent
모델에서 children
속성을 읽을 때 children_count
속성을 함께 읽도록 하려면 다음과 같이 코드를 작성합니다.
class Parent(Base):
__tablename__ = "parent_table"
id = Column(Integer, primary_key=True)
children = relationship(
"Child",
back_populates="parent",
properties={"children_count": lambda: len(children)},
)
class Child(Base):
__tablename__ = "child_table"
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("parent_table.id"))
parent = relationship("Parent", back_populates="children")
예제 코드
from sqlalchemy import Column, Integer, ForeignKey, relationship
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Parent(Base):
__tablename__ = "parent_table"
id = Column(Integer, primary_key=True)
children = relationship("Child", back_populates="parent")
class Child(Base):
__tablename__ = "child_table"
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("parent_table.id"))
parent = relationship("Parent", back_populates="children")
engine = create_engine("sqlite:///example.db")
Base.metadata.create_all(engine)
session = sessionmaker(bind=engine)()
parent = Parent()
child1 = Child(parent=parent)
child2 = Child(parent=parent)
session.add_all([parent, child1, child2])
session.commit()
# parent.children 에는 child1, child2 가 포함됩니다.
# child1.parent 와 child2.parent 는 parent 를 참조합니다.
print(parent.children)
print(child1.parent)
print(child2.parent)
session.close()
이 코드는 다음과 같은 테이블을 생성합니다.
CREATE TABLE parent_table (
id INTEGER PRIMARY KEY
);
CREATE TABLE child_table (
id INTEGER PRIMARY KEY,
parent_id INTEGER FOREIGN KEY (parent_table.id)
);
코드를 실행하면 다음과 같은 결과가 출력됩니다.
[<Child(id=1, parent_id=1)>, <Child(id=2, parent_id=1)>]
<Parent(id=1, children=[<Child(id=1, parent_id=1)>, <Child(id=2, parent_id=1)>])>
<Parent(id=1, children=[<Child(id=1, parent_id=1)>, <Child(id=2, parent_id=1)>])>
back_populates 대체 방법
relationship 함수의 두 번째 매개변수 사용
relationship 함수의 두 번째 매개변수는 관계의 반대쪽 모델을 지정하는 데 사용됩니다. 예를 들어, Parent
모델과 Child
모델 간에 양방향 관계를 정의하려면 다음과 같이 코드를 작성합니다.
class Parent(Base):
__tablename__ = "parent_table"
id = Column(Integer, primary_key=True)
children = relationship("Child", foreign_keys=[parent_id])
class Child(Base):
__tablename__ = "child_table"
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("parent_table.id"))
parent = relationship(Parent, foreign_keys=[parent_id])
@relationship 데코레이터 사용
from sqlalchemy.orm import relationship
class Parent(Base):
__tablename__ = "parent_table"
id = Column(Integer, primary_key=True)
@relationship(lambda: Child)
def children(self):
return Child.query.filter(Child.parent_id == self.id)
class Child(Base):
__tablename__ = "child_table"
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("parent_table.id"))
@relationship(lambda: Parent)
def parent(self):
return Parent.query.filter(Parent.id == self.parent_id)
직접 SQL 쿼리 사용
from sqlalchemy import select
class Parent(Base):
__tablename__ = "parent_table"
id = Column(Integer, primary_key=True)
def children(self):
return Child.query.filter(Child.parent_id == self.id)
class Child(Base):
__tablename__ = "child_table"
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey("parent_table.id"))
def parent(self):
return Parent.query.filter(Parent.id == self.parent_id)
parent = Parent.query.get(1)
children = parent.children()
python sqlalchemy