본문 바로가기
C.W.K.
Stream
Lesson 05 of 05 · published

Pydantic — 외부 입력을 실행 중에 검증하기

~18 min · pydantic, validation, fastapi, runtime

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

Pydantic의 BaseModel은 어노테이션을 읽어 생성 시 타입과 필수 필드를 검사하고 구조화된 ValidationError를 내. Field로 범위·길이와 메타데이터를 붙이고 가변 기본값에는 default_factory를 써.

v2의 직렬화는 model_dump 계열이고 v1의 dict와 섞지 마. 문자열 '42'를 정수로 바꾸는 강제 변환이 친절할 때도 있지만 내부 프로토콜 오류를 숨길 수도 있으므로 외부 사용자 입력과 엄격한 내부 경계를 다르게 정해. FastAPI가 이 모델을 요청·응답에 써.

Code

BaseModel과 Field로 값 검증하기·python
# pip install pydantic
from pydantic import BaseModel, Field

class User(BaseModel):
    name: str
    age: int = Field(ge=0, le=150)
    email: str | None = None
    tags: list[str] = Field(default_factory=list)

# dict 에서 생성
u = User(name="alice", age=30)
print(u)                              # name='alice' age=30 email=None tags=[]
print(u.name, u.age)

# 생성 시 검증
try:
    bad = User(name="alice", age=200)        # age 범위 밖
except Exception as e:
    print("ValidationError:", str(e)[:200])

# 타입 강제 — '30' 이 30 됨
u2 = User(name="bob", age="30")
print(u2.age, type(u2.age))           # 30 <class 'int'>
JSON으로 내보내고 다시 읽기·python
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int
    tags: list[str] = []

u = User(name="alice", age=30, tags=["admin", "user"])

# Pydantic v2
print(u.model_dump())                 # dict
print(u.model_dump_json())            # JSON 문자열

# Round-trip
from_json = User.model_validate_json(u.model_dump_json())
print(from_json == u)                 # True

# Pydantic v1 은 .dict() 와 .json() — 다른 메서드 이름
ValidationError의 위치와 메시지·python
from pydantic import BaseModel, ValidationError, Field

class Order(BaseModel):
    item: str = Field(min_length=1)
    quantity: int = Field(gt=0)
    price: float = Field(ge=0.0)

try:
    Order(item="", quantity=-1, price=-5)
except ValidationError as e:
    for err in e.errors():
        print(err["loc"], err["msg"])

# 출력:
# ('item',)        String should have at least 1 character
# ('quantity',)    Input should be greater than 0
# ('price',)       Input should be greater than or equal to 0
중첩 모델 조합하기·python
from pydantic import BaseModel

class Address(BaseModel):
    street: str
    city: str
    zip: str

class User(BaseModel):
    name: str
    addresses: list[Address] = []

u = User(
    name="alice",
    addresses=[
        {"street": "123 Main", "city": "Seoul", "zip": "01234"},
        {"street": "456 Oak", "city": "Busan", "zip": "56789"},
    ],
)
# 중첩 dict 자동 검증 + Address 인스턴스로 변환
print(u.addresses[0].city)            # 'Seoul'
print(type(u.addresses[0]))           # <class '...Address'>
FastAPI 요청 경계의 Pydantic·python
# Pippa 의 chat 라우트가 Pydantic 어떻게 쓰는지 sketch
from pydantic import BaseModel

class ChatMessage(BaseModel):
    role: str  # 'user' | 'assistant' (더 빡빡엔 Literal)
    content: str
    timestamp: float | None = None

class ChatRequest(BaseModel):
    conversation_id: str
    message: ChatMessage
    brain: str = "claude"
    extended_thinking: bool = False

class ChatResponse(BaseModel):
    conversation_id: str
    message_id: str
    content: str
    brain: str

# FastAPI 에서:
# @router.post('/api/chat', response_model=ChatResponse)
# async def chat(req: ChatRequest) -> ChatResponse:
#     ...
# FastAPI 가 요청 body 자동 검증, 응답 자동 직렬화.

External links

Exercise

name, tracks, difficulty, estimated_hours를 가진 Quest BaseModel을 만들고 이름 길이·난이도 Literal·양수 시간 제약을 줘. 유효값과 세 잘못된 값을 만들어 오류의 loc와 msg를 출력하고 JSON 왕복도 확인해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인 — 댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.