관계 읽기
관계 읽기 (Read Relationships)
이제 관계 속성으로 데이터를 연결하는 방법을 알았으니, 관계에서 객체를 가져와서 읽는 방법을 살펴볼게요.
출처: 공식문서
히어로 선택하기
먼저 작업을 시작할 히어로 하나를 가져오는 select_heroes() 함수를 추가하고, 그 함수를 main() 함수에 넣어요:
# Code above omitted 👆
def select_heroes():
with Session(engine) as session:
statement = select(Hero).where(Hero.name == "Spider-Boy")
result = session.exec(statement)
hero_spider_boy = result.one()
# Code here omitted 👈
def main():
create_db_and_tables()
create_heroes()
select_heroes()
# Code below omitted 👇
관련 팀 선택하기 - 예전 방식
이제 히어로가 있으니, 이 히어로가 속한 팀을 가져올 수 있어요.
지금까지 배운 것으로는 select() 문을 만들고 session.exec()로 실행한 다음 .first() 결과를 얻을 수 있죠. 예를 들면:
# Code above omitted 👆
def select_heroes():
with Session(engine) as session:
statement = select(Hero).where(Hero.name == "Spider-Boy")
result = session.exec(statement)
hero_spider_boy = result.one()
statement = select(Team).where(Team.id == hero_spider_boy.team_id)
result = session.exec(statement)
team = result.first()
print("Spider-Boy's team:", team)
# Code below omitted 👇
관계 팀 가져오기 - 새로운 방식
하지만 이제 관계 속성이 있으니 그냥 접근하면 돼요. SQLModel(정확히는 SQLAlchemy)이 데이터베이스에서 해당 데이터를 가져와서 속성에 넣어 줄 거예요. ✨
그러니까 위의 강조된 블록은 아래 블록과 같은 결과를 줘요:
# Code above omitted 👆
def select_heroes():
with Session(engine) as session:
statement = select(Hero).where(Hero.name == "Spider-Boy")
result = session.exec(statement)
hero_spider_boy = result.one()
# Code here omitted 👈
print("Spider-Boy's team again:", hero_spider_boy.team)
# Code below omitted 👇
💡 팁
자동 데이터 가져오기는 시작 객체(여기선
Hero)가 열려 있는 세션과 연결되어 있는 한 동작해요.예를 들어 여기처럼
Session객체가 있는with블록 안이면 되죠.
관계 객체 리스트 가져오기
그리고 같은 방식으로, 일대다 관계의 다(多) 쪽을 작업할 때는 관계 속성에 접근하는 것만으로 관련 객체들의 리스트를 얻을 수 있어요:
# Code above omitted 👆
def select_heroes():
with Session(engine) as session:
statement = select(Team).where(Team.name == "Preventers")
result = session.exec(statement)
team_preventers = result.one()
print("Preventers heroes:", team_preventers.heroes)
# Code below omitted 👇
👀 전체 파일 미리보기 (Full file preview)
from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select
class Team(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
headquarters: str
heroes: list["Hero"] = Relationship(back_populates="team")
class Hero(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
name: str = Field(index=True)
secret_name: str
age: int | None = Field(default=None, index=True)
team_id: int | None = Field(default=None, foreign_key="team.id")
team: Team | None = Relationship(back_populates="heroes")
sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"
engine = create_engine(sqlite_url, echo=True)
def create_db_and_tables():
SQLModel.metadata.create_all(engine)
def create_heroes():
with Session(engine) as session:
team_preventers = Team(name="Preventers", headquarters="Sharp Tower")
team_z_force = Team(name="Z-Force", headquarters="Sister Margaret's Bar")
hero_deadpond = Hero(
name="Deadpond", secret_name="Dive Wilson", team=team_z_force
)
hero_rusty_man = Hero(
name="Rusty-Man", secret_name="Tommy Sharp", age=48, team=team_preventers
)
hero_spider_boy = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
session.add(hero_deadpond)
session.add(hero_rusty_man)
session.add(hero_spider_boy)
session.commit()
session.refresh(hero_deadpond)
session.refresh(hero_rusty_man)
session.refresh(hero_spider_boy)
print("Created hero:", hero_deadpond)
print("Created hero:", hero_rusty_man)
print("Created hero:", hero_spider_boy)
hero_spider_boy.team = team_preventers
session.add(hero_spider_boy)
session.commit()
session.refresh(hero_spider_boy)
print("Updated hero:", hero_spider_boy)
hero_black_lion = Hero(name="Black Lion", secret_name="Trevor Challa", age=35)
hero_sure_e = Hero(name="Princess Sure-E", secret_name="Sure-E")
team_wakaland = Team(
name="Wakaland",
headquarters="Wakaland Capital City",
heroes=[hero_black_lion, hero_sure_e],
)
session.add(team_wakaland)
session.commit()
session.refresh(team_wakaland)
print("Team Wakaland:", team_wakaland)
hero_tarantula = Hero(name="Tarantula", secret_name="Natalia Roman-on", age=32)
hero_dr_weird = Hero(name="Dr. Weird", secret_name="Steve Weird", age=36)
hero_cap = Hero(
name="Captain North America", secret_name="Esteban Rogelios", age=93
)
team_preventers.heroes.append(hero_tarantula)
team_preventers.heroes.append(hero_dr_weird)
team_preventers.heroes.append(hero_cap)
session.add(team_preventers)
session.commit()
session.refresh(hero_tarantula)
session.refresh(hero_dr_weird)
session.refresh(hero_cap)
print("Preventers new hero:", hero_tarantula)
print("Preventers new hero:", hero_dr_weird)
print("Preventers new hero:", hero_cap)
def select_heroes():
with Session(engine) as session:
statement = select(Team).where(Team.name == "Preventers")
result = session.exec(statement)
team_preventers = result.one()
print("Preventers heroes:", team_preventers.heroes)
def update_heroes():
with Session(engine) as session:
statement = select(Hero).where(Hero.name == "Spider-Boy")
result = session.exec(statement)
hero_spider_boy = result.one()
hero_spider_boy.team = None
session.add(hero_spider_boy)
session.commit()
session.refresh(hero_spider_boy)
print("Spider-Boy without team:", hero_spider_boy)
def main():
create_db_and_tables()
create_heroes()
select_heroes()
update_heroes()
if __name__ == "__main__":
main()
이렇게 하면 Preventers 팀의 모든 히어로가 담긴 리스트를 출력하게 돼요.
정리
관계 속성을 사용하면 평범한 Python 객체의 힘을 이용해서 데이터베이스의 관련 데이터에 쉽게 접근할 수 있어요. 😎