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()로 해결했지만, 모델 구조가 복잡해지면 리팩토링을 고려해야 할 것 같다.