Dev/Python

SQLAlchemy 관계 종류

lumination 2025. 4. 17. 10:23

1:1 (일대일)

예: 유저(User)는 하나의 프로필(Profile)만 가짐

# user.py
class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    username = Column(String)
    profile = relationship("Profile", back_populates="user", uselist=False)

# profile.py
class Profile(Base):
    __tablename__ = "profiles"
    id = Column(Integer, primary_key=True)
    bio = Column(String)
    user_id = Column(Integer, ForeignKey("users.id"))
    user = relationship("User", back_populates="profile")
  • uselist=False → 관계가 리스트가 아니라 단일 객체임을 의미
  • User.profile ↔ Profile.user 1:1 연결

1:N (일대다)

예: 유저(User)는 여러 개의 게시글(Post)을 작성할 수 있음

# user.py
class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    username = Column(String)
    posts = relationship("Post", back_populates="owner")

# post.py
class Post(Base):
    __tablename__ = "posts"
    id = Column(Integer, primary_key=True)
    title = Column(String)
    owner_id = Column(Integer, ForeignKey("users.id"))
    owner = relationship("User", back_populates="posts")
  • User.posts → 게시글 목록 (list)
  • Post.owner → 해당 글의 작성자 (1명)

M:N (다대다)

예: 학생(Student)은 여러 수업(Course)을 듣고,
수업(Course)은 여러 학생이 들을 수 있음

# 중간 테이블
association_table = Table(
    "student_course",
    Base.metadata,
    Column("student_id", ForeignKey("students.id"), primary_key=True),
    Column("course_id", ForeignKey("courses.id"), primary_key=True),
)

# student.py
class Student(Base):
    __tablename__ = "students"
    id = Column(Integer, primary_key=True)
    name = Column(String)
    courses = relationship("Course", secondary=association_table, back_populates="students")

# course.py
class Course(Base):
    __tablename__ = "courses"
    id = Column(Integer, primary_key=True)
    title = Column(String)
    students = relationship("Student", secondary=association_table, back_populates="courses")
  • secondary=association_table 로 중간 테이블 지정
  • Student.courses → 수강 중인 수업 목록
  • Course.students → 수업을 듣는 학생 목록
# 데이터 삽입 예시
    # 학생 생성
    student1 = Student(name="Alice")
    student2 = Student(name="Bob")

    # 수업 생성
    course1 = Course(title="Math")
    course2 = Course(title="Physics")

    # 관계 연결
    student1.courses.append(course1)     # Alice는 Math 듣고
    student1.courses.append(course2)     # Physics도 듣고
    student2.courses.append(course1)     # Bob은 Math만 들음

    # 세션에 추가
    session.add_all([student1, student2, course1, course2])
    session.commit()
    
# 데이터 조회 예시
	# 특정 학생이 듣는 수업들	
        alice = session.query(Student).filter_by(name="Alice").first()
        for course in alice.courses:
            print(course.title)  # Math, Physics

	# 특정 수업을 듣는 학생들
        math = session.query(Course).filter_by(title="Math").first()
        for student in math.students:
            print(student.name)  # Alice, Bob

# 관계 제거 (수업 삭제)
alice = session.query(Student).filter_by(name="Alice").first()
physics = session.query(Course).filter_by(title="Physics").first()

alice.courses.remove(physics)  # Alice가 Physics 수업 그만둠
session.commit()