sqlalchemy의 declarative_base()를 fastapi에서 사용하는 이유
1. declarative_base()를 사용하는 이유
- SQLAlchemy에는 크게 두 가지 방식의 ORM이 있다.
1. Declarative ORM 방식 (클래스를 테이블처럼 사용)
2. Imperative (Core) 방식 (SQLAlchemy의 Table 객체를 직접 사용)
- declarative_base()를 사용하면 클래스를 통해 테이블을 정의할 수 있으며, Pythonic한 방식으로 ORM을 사용할 수 있다. 이를 사용하면 다음과 같은 장점이 있다:
✅ 객체 지향적인 코드 작성 → Python 클래스를 테이블처럼 활용
✅ 자동 테이블 생성 및 관리 → Base.metadata.create_all(engine)을 통해 테이블 자동 생성
✅ 관계(Relationship) 표현 가능 → relationship을 사용하여 쉽게 테이블 간 관계 설정 가능
✅ 코드 가독성 증가 → 클래스 기반의 테이블 정의 방식으로 직관적인 코드 작성 가능
✅ Pydantic과의 호환성 → FastAPI에서 Pydantic 모델과 쉽게 연동 가능
2. declarative_base() 기본 사용법
- declarative_base()를 사용하면 테이블을 Python 클래스로 정의할 수 있다.
- 기본적인 테이블 정의
- Base = declarative_base() → Base를 상속받아 모든 모델을 정의
- __tablename__ → 데이터베이스 테이블 이름 설정
- Column을 이용하여 테이블 컬럼 정의
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import declarative_base, sessionmaker
Base = declarative_base() # 모든 ORM 모델의 부모 클래스
class User(Base):
__tablename__ = "users" # 테이블 이름 지정
id = Column(Integer, primary_key=True, index=True) # 기본키
name = Column(String, nullable=False) # 문자열 컬럼
age = Column(Integer) # 정수 컬럼
# 데이터베이스 연결
DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL, echo=True)
Base.metadata.create_all(bind=engine) # 테이블 자동 생성
3. declarative_base()에서 활용 가능한 주요 기능
1) __tablename__을 이용한 테이블 이름 설정
- 각 모델 클래스에서 __tablename__을 정의하여 데이터베이스 테이블 이름을 직접 설정할 수 있다.
class Product(Base):
__tablename__ = "products"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
2) Column을 이용한 다양한 데이터 타입 설정
- Column을 사용하면 SQLAlchemy에서 제공하는 여러 데이터 타입을 사용할 수 있다.
from sqlalchemy import Boolean, DateTime, Float, Text
from datetime import datetime
class Order(Base):
__tablename__ = "orders"
id = Column(Integer, primary_key=True, index=True)
price = Column(Float, nullable=False) # 실수 타입
description = Column(Text) # 긴 문자열 저장
is_paid = Column(Boolean, default=False) # Boolean 타입
created_at = Column(DateTime, default=datetime.utcnow) # 생성 시간
3) relationship을 이용한 테이블 간 관계 설정
- SQLAlchemy ORM에서 relationship을 사용하면 1:1, 1:N, N:M 관계를 쉽게 설정할 수 있다.
1. 1:N 관계 (One-to-Many)
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
# 1:N 관계 설정 (User -> Post)
posts = relationship("Post", back_populates="owner")
class Post(Base):
__tablename__ = "posts"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, nullable=False)
user_id = Column(Integer, ForeignKey("users.id")) # 외래 키 설정
# 역방향 관계
owner = relationship("User", back_populates="posts")
4. __mapper_args__의 다양한 활용 예제
1) 다형성 설정 (객체 타입에 따라 다르게 매핑)
- polymorphic_on: 해당 컬럼의 값을 기준으로 상속된 클래스를 구분
- polymorphic_identity: 이 클래스의 기본 유형을 설정
class Employee(Base):
__tablename__ = "employees"
id = Column(Integer, primary_key=True, index=True)
type = Column(String, nullable=False)
__mapper_args__ = {
"polymorphic_identity": "employee", # 기본 유형을 'employee'로 설정
"polymorphic_on": type # 다형성을 적용할 기준 컬럼
}
2) Versioning (버전 관리) 설정 (데이터 변경 시 버전 번호 증가)
- version_id_col: 데이터 변경 시 자동으로 증가하는 버전 관리 컬럼
class Document(Base):
__tablename__ = "documents"
id = Column(Integer, primary_key=True, index=True)
version = Column(Integer, nullable=False, default=1)
__mapper_args__ = {
"version_id_col": version # 변경 시 자동 증가할 버전 컬럼
}
3) 테이블 자동 로드 설정 (기존 DB 테이블을 자동으로 로드)
class AutoLoadTable(Base):
__tablename__ = "autoload_table"
__mapper_args__ = {
"autoload": True # 테이블 스키마 자동 로드
}
4) 기본 정렬 기준 설정 (쿼리 결과 기본 정렬)
class Product(Base):
__tablename__ = "products"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
__mapper_args__ = {
"order_by": name # 기본 정렬을 'name' 컬럼 기준으로 설정
}
5) Abstract Base Class 설정 (공통 속성을 가지는 기본 클래스 정의)
- __abstract__ = True: 이 클래스를 직접 테이블로 생성하지 않고 상속 전용으로 사용
class BaseModel(Base):
__abstract__ = True # 이 클래스 자체는 테이블을 생성하지 않음
id = Column(Integer, primary_key=True, index=True)
class User(BaseModel):
__tablename__ = "users"
name = Column(String, nullable=False)
'SQLAlchemy' 카테고리의 다른 글
Mapped와 DynamicMapped의 정리 - 1:1, 1:n, n:m & uselist 포함 (0) | 2025.02.17 |
---|---|
__table_args__ 메소드 정리 (0) | 2025.02.13 |
[SQLALchemy] 트랜잭션(Transaction) 그리고 Database Lock (0) | 2025.02.04 |
[SQLALchemy] 비동기 함수, 비동기 Database 그리고 Pool의 정리 (0) | 2025.02.01 |
[SQLALchemy] 세션(Session), 비동기 세션(Async Session) 그리고 scoped_session의 정리 (0) | 2025.02.01 |
댓글