본문 바로가기

Tech/SQLAlchemy

[SQLAlchemy] 연관관계 설정

반응형

ORM 에서는 매핑된 객체들이 서로를 참조하는 구조를 연관관계를 통해서 표현한다.
SQLAlchemy 에서는 relationship() 메서드를 사용하여 매핑된 모델 클래스를 정의할 때 연관관계를 표현한다.
연관관계는 1대1, 1대N, N대1, N대M 등의 구조로 이루어져 있다.

1. sqlalchemy.orm.relationship

SQLAlchemy 에서는 relationship() 메서드를 사용하여 두 객체 클래스의 연관관계를 지정한다.
relationship() 메서드에 연관관계를 맺으려는 클래스의 이름을 입력하여 참조 객체를 생성한다.

 

from sqlalchemy.orm import relationship


class User(Base):
    __tablename__ = "user"

    # ...

    team_id = Column(Integer, ForeignKey("team.id"))


class Team(Base):
    __tablename__ = "team"

    # ...

    users = relationship("User")


위의 예제는 Team 과 User 객체의 연관관계를 구현한 것이다. 두 객체는  Team 하나에 여러 User 가 포함되는 1 대 N 관계를 가지고 있다.

Team 클래스는 users 라는 객체를 가지고 있는데, 이는 데이터베이스 테이블에 실제 컬럼으로 존재하는 필드는 아니고 파이썬 코드에서만 사용 가능한 참조 변수이다. 이 변수는 해당 Team 에 연관관계를 가지고 있는 User 객체들을 포함하고 있는 참조변수로 이 변수를 통해서 User 들에 쉽게 접근할 수 있다.

2. relationship patterns

연관관계의 종류는 one to many, many to one, one to one, many to many 등으로 분류된다. 각 연관관계 별 동작 구성과 구현에 대해서 각각 정리한다.

1) one to many

one to many 관계는 1대N 관계로 자식 테이블이 부모 테이블을 외래키로 참조하는 관계를 객체로 구현하는 것이다. 이때 부모 테이블에 해당하는 객체는 relationship() 메서드를 통해서 자식 객체를 참조하는 참조 변수를 가지게 되는데, 이때 참조 변수는 N 개의 자식을 참조하기 때문에 리스트 형식이 된다.

이때 만약 자식 객체에서도 부모 객체에 접근하고 싶은 경우에는 relationship.back_populates 속성을 사용하여 설정을 해준다. back_populates 속성으로 특정 속성을 지정해두면 해당 객체의 값이 변할 때 연관된 객체에서 지정된 속성을 찾아서 값을 동기화 해준다. 아래의 예시의 경우 User 객체의 team 이 변경되면 기존 Team 객체의 users 에서 User 객체가 삭제되고 변경된 Team 객체의 users 에 User 객체가 추가되어 값이 동기화 된다.

 

from sqlalchemy.orm import relationship


class User(Base):
    __tablename__ = "user"

    # ...

    team_id = Column(Integer, ForeignKey("team.id")) # 자식 객체는 외래키로 부모 객체를 참조한다.
    team = relationship("Team", back_populates="users") # 부모 객체를 참조하는 참조 변수


class Team(Base):
    __tablename__ = "team"

    # ...

    users = relationship("User", back_populates="team") # 자식 객체들을 참조하는 참조 변수

 

2) many to one

many to one 은 N대1 관계를 의미한다. one to many 와 반대로 부모 객체가 자식 객체를 외래키로 참조하고, 자식 객체가 relationship 으로 부모 객체 클래스의 객체들을 참조하는 리스트를 가지게 된다.

3) one to one

one to one 은 1대1 관계로 필수적으로 양방향 참조가 가능하도록 구현해야한다. one to many 에서 양쪽이 서로 참조가 가능하도록 구현한 상태에서 one 의 역할에 있는 클래스가 대상 객체를 여러개가 아닌 하나만 참조하도록 변경해주면 된다. 이때 relationship.uselist 속성을 False 로 지정해주면 collection 이 아닌 single object 를 참조하게 된다.

 

class User(Base):
    __tablename__ = "user"

    # ...

    team_id = Column(Integer, ForeignKey("team.id"))
    team = relationship("Team", back_populates="user") # many-to-one 관계의 참조 변수


class Team(Base):
    __tablename__ = "team"

    # ...

    # one-to-many 의 참조 변수. uselist 를 False 로 설정하여 하나의 객체만 참조하도록 설정
    user = relationship("User", back_populates="team", uselist=False)

 

4) many to many

many to many 는 N대M 의 관계를 표현한 것으로 두 객체 사이에 연관 테이블을 추가하여 연관관계를 구현하도록 한다. 연관 테이블은 relationship.secondary 속성으로 지정된다.

 

association_table = Table(
        "association",
        Base.metadata,
        Column("left_id", ForeignKey("left.id"), primary_key=True),
        Column("right_id", ForeignKey("right.id"), primary_key=True)
    )

class Left(Base):
    __tablename__ = "left"
    # ...
    rights = relationship("Right", secondary=association_table, back_populates="lefts")


class Right(Base):
    __tablename__ = "right"
    # ...
    lefts = relationship("Left", secondary=association_table, back_populates="rights")

[Reference]

- https://docs.sqlalchemy.org/en/14/orm/basic_relationships.html

 

Basic Relationship Patterns — SQLAlchemy 1.4 Documentation

Basic Relationship Patterns A quick walkthrough of the basic relational patterns. The imports used for each of the following sections is as follows: from sqlalchemy import Column, ForeignKey, Integer, Table from sqlalchemy.orm import declarative_base, rela

docs.sqlalchemy.org

 

반응형

'Tech > SQLAlchemy' 카테고리의 다른 글

[SQLAlchemy] imperative mapping  (0) 2023.11.11
[SQLAlchemy] Relationship - CASCADE  (0) 2023.11.06
[SQLAlchemy] SQLAlchemy 기본 설명  (0) 2022.07.17