관계 읽기

관계 읽기 (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 객체의 힘을 이용해서 데이터베이스의 관련 데이터에 쉽게 접근할 수 있어요. 😎

더 알아보기 (Learn more)