728x90

다양한 프레임워크와 ORM 도구에서 데이터 모델을 정의하는데 사용되는 파일로, 데이터베이스 테이블 구조를 코드로 표현

주 구성요소

  • 테이블을 나타내는 클래스 정의
  • 각 클래스 내에 속성 정의 (테이블 컬럼 정의)
  • 테이블 간의 관계 정의 (Foreign key, one to one, many to many 등)
  • 모델의 메타데이터 정의 
  • 필요한 인덱스, 제약조건 등 정의
  • 모델 검증을 위한 로직 (잘못된 입력 방지 및 특정 규칙 적용)
  • 데이터베이스 마이그레이션을 위한 설정
from sqlmodel import Field, Relationship, SQLModel


# Shared properties
# TODO replace email str with EmailStr when sqlmodel supports it
class UserBase(SQLModel):
    email: str = Field(unique=True, index=True)
    is_active: bool = True
    is_superuser: bool = False
    full_name: str | None = None


# Properties to receive via API on creation
class UserCreate(UserBase):
    password: str


# TODO replace email str with EmailStr when sqlmodel supports it
class UserCreateOpen(SQLModel):
    email: str
    password: str
    full_name: str | None = None


# Properties to receive via API on update, all are optional
# TODO replace email str with EmailStr when sqlmodel supports it
class UserUpdate(UserBase):
    email: str | None = None
    password: str | None = None


# TODO replace email str with EmailStr when sqlmodel supports it
class UserUpdateMe(SQLModel):
    full_name: str | None = None
    email: str | None = None


class UpdatePassword(SQLModel):
    current_password: str
    new_password: str


# Database model, database table inferred from class name
class User(UserBase, table=True):
    id: int | None = Field(default=None, primary_key=True)
    hashed_password: str
    items: list["Item"] = Relationship(back_populates="owner")


# Properties to return via API, id is always required
class UserOut(UserBase):
    id: int


class UsersOut(SQLModel):
    data: list[UserOut]
    count: int


# Shared properties
class ItemBase(SQLModel):
    title: str
    description: str | None = None


# Properties to receive on item creation
class ItemCreate(ItemBase):
    title: str


# Properties to receive on item update
class ItemUpdate(ItemBase):
    title: str | None = None


# Database model, database table inferred from class name
class Item(ItemBase, table=True):
    id: int | None = Field(default=None, primary_key=True)
    title: str
    owner_id: int | None = Field(default=None, foreign_key="user.id", nullable=False)
    owner: User | None = Relationship(back_populates="items")


# Properties to return via API, id is always required
class ItemOut(ItemBase):
    id: int
    owner_id: int


class ItemsOut(SQLModel):
    data: list[ItemOut]
    count: int


# Generic message
class Message(SQLModel):
    message: str


# JSON payload containing access token
class Token(SQLModel):
    access_token: str
    token_type: str = "bearer"


# Contents of JWT token
class TokenPayload(SQLModel):
    sub: int | None = None


class NewPassword(SQLModel):
    token: str
    new_password: str

 

특징 및 장점

  • 코드가 간결하며, Pydantic 및 SQLModel을 사용하여 모델을 정의하고 데이터베이스 테이블을 생성
  • UserBase를 기반으로 하는 다양한 파생 클래스들이 있는데 공통된 속성을 하위 클래스에서 확장하여 사용하는 방식이 효과적이며, 코드 재사용성을 높임
  • Pydantic 모델은 FastAPI에서 사용하기에 이상적이며, API의 요청 및 응답에 대한 유효성 검사 및 자동 문서화를 제공
  • 모델 정의에서 데이터베이스 테이블 정의까지 일관된 패턴을 사용하고 있어 코드의 이해와 유지보수에 유리
  • UsersOut 및 ItemsOut과 같은 응답 모델을 정의하여 API 응답에 대한 구조를 명확하게 나타냄

주의할 점

  • 클래스 이름을 기반으로 한 암시적인 테이블 이름이 사용되고 있음 (명시적인 테이블 이름 정의가 필요할 수 있음)
  • 모델 정의에 클래스 계층 구조가 있어 데이터베이스와 API 간의 복잡한 관계에서는 코드의 이해가 어려워질 수 있음
  • SQLModel이 EmailStr를 지원하지 않을 때까지 email 속성은 일반 문자열로 남아있음 (주석에도 명시됨)
  • owner_id와 user.id 간의 Foreign Key 관계가 암시적으로 정의되어 있음 (명시적인 Foreign Key 제약이 필요할 수 있음)

참고 : FastAPI 개발자가 직접 개발한 FastAPI backend 시리즈

FastAPI 개발자가 직접 개발한 FastAPI backend 프로젝트 구조

FastAPI 개발자가 직접 개발한 FastAPI backend alembic

FastAPI 개발자가 직접 개발한 FastAPI backend DB 초기화 방법

FastAPI 개발자가 직접 개발한 FastAPI backend pyproject.toml

FastAPI 개발자가 직접 개발한 FastAPI backend 설정파일 config.py

FastAPI 개발자가 직접 개발한 FastAPI backend 데이터모델 models.py

 

728x90

+ Recent posts