FastAPI에서 Pydantic 모델 재사용하며 겪은 순환 참조 문제

문제 상황

사용자와 게시물 간의 관계를 표현하는 API를 만들던 중, Pydantic 모델에서 순환 참조 에러가 발생했다.

from pydantic import BaseModel
from typing import List

class User(BaseModel):
    id: int
    name: str
    posts: List['Post']  # NameError 발생

class Post(BaseModel):
    id: int
    title: str
    author: User

NameError: name 'Post' is not defined 에러가 발생했다. Python은 순차적으로 코드를 읽기 때문에 User 클래스 정의 시점에 Post는 아직 정의되지 않은 상태였다.

해결 방법

from __future__ import annotations를 사용하고 update_forward_refs()를 호출하는 방식으로 해결했다.

from __future__ import annotations
from pydantic import BaseModel
from typing import List, Optional

class User(BaseModel):
    id: int
    name: str
    posts: Optional[List[Post]] = None

class Post(BaseModel):
    id: int
    title: str
    author: Optional[User] = None

User.update_forward_refs()
Post.update_forward_refs()

__future__ 임포트를 통해 타입 힌트가 문자열로 처리되고, update_forward_refs()가 모든 클래스 정의 후 실제 타입으로 연결해준다.

추가 고려사항

실제로는 순환 참조 자체를 피하는 게 더 나은 설계일 수 있다. Response 모델을 별도로 분리하거나, 필요한 필드만 포함하는 방식도 검토했다.

class UserResponse(BaseModel):
    id: int
    name: str

class PostResponse(BaseModel):
    id: int
    title: str
    author: UserResponse

당장은 update_forward_refs()로 해결했지만, 모델 구조가 복잡해지면 리팩토링을 고려해야 할 것 같다.

FastAPI에서 Pydantic 모델 재사용하며 겪은 순환 참조 문제