11 KiB
11 KiB
Pydantic ConfigDict 사용 매뉴얼
개요
Pydantic v2에서 ConfigDict는 모델의 유효성 검사, 직렬화, JSON 스키마 생성 등의 동작을 제어하는 설정을 정의하는 TypedDict입니다.
Pydantic v1의
class Config는 더 이상 권장되지 않으며,ConfigDict를 사용해야 합니다.
기본 사용법
from pydantic import BaseModel, ConfigDict
class MyModel(BaseModel):
model_config = ConfigDict(
str_strip_whitespace=True,
strict=True
)
name: str
age: int
설정 옵션 전체 목록
문자열 처리
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
str_to_lower |
bool |
False |
문자열을 소문자로 변환 |
str_to_upper |
bool |
False |
문자열을 대문자로 변환 |
str_strip_whitespace |
bool |
False |
문자열 앞뒤 공백 제거 |
str_min_length |
int | None |
None |
문자열 최소 길이 |
str_max_length |
int | None |
None |
문자열 최대 길이 |
예시:
class UserInput(BaseModel):
model_config = ConfigDict(
str_strip_whitespace=True,
str_to_lower=True,
str_min_length=1,
str_max_length=100
)
username: str
user = UserInput(username=" HELLO ")
print(user.username) # "hello"
유효성 검사
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
strict |
bool |
False |
엄격한 타입 검사 활성화 (타입 강제 변환 비활성화) |
validate_assignment |
bool |
False |
속성 할당 시 유효성 검사 수행 |
validate_default |
bool |
False |
기본값도 유효성 검사 수행 |
validate_return |
bool |
False |
반환값 유효성 검사 |
revalidate_instances |
Literal['always', 'never', 'subclass-instances'] |
'never' |
모델 인스턴스 재검증 시점 |
arbitrary_types_allowed |
bool |
False |
Pydantic이 지원하지 않는 타입 허용 |
예시 - strict 모드:
class StrictModel(BaseModel):
model_config = ConfigDict(strict=True)
count: int
# strict=False (기본값): "123" -> 123 자동 변환
# strict=True: "123" 입력 시 ValidationError 발생
예시 - validate_assignment:
class User(BaseModel):
model_config = ConfigDict(validate_assignment=True)
age: int
user = User(age=25)
user.age = "invalid" # ValidationError 발생
Extra 필드 처리
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
extra |
'allow' | 'ignore' | 'forbid' |
'ignore' |
추가 필드 처리 방식 |
값 설명:
'ignore': 추가 필드 무시 (기본값)'allow': 추가 필드 허용,__pydantic_extra__에 저장'forbid': 추가 필드 입력 시 에러 발생
예시:
class AllowExtra(BaseModel):
model_config = ConfigDict(extra='allow')
name: str
data = AllowExtra(name="John", unknown_field="value")
print(data.__pydantic_extra__) # {'unknown_field': 'value'}
class ForbidExtra(BaseModel):
model_config = ConfigDict(extra='forbid')
name: str
ForbidExtra(name="John", unknown="value") # ValidationError 발생
불변성 (Immutability)
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
frozen |
bool |
False |
모델을 불변(immutable)으로 만듦, __hash__() 구현 |
예시:
class ImmutableUser(BaseModel):
model_config = ConfigDict(frozen=True)
name: str
age: int
user = ImmutableUser(name="John", age=30)
user.age = 31 # 에러 발생: Instance is frozen
# frozen=True이면 해시 가능
users_set = {user} # 정상 작동
별칭 (Alias) 설정
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
populate_by_name |
bool |
False |
필드명과 별칭 모두로 값 설정 허용 (deprecated) |
validate_by_alias |
bool |
True |
별칭으로 필드 값 설정 허용 |
validate_by_name |
bool |
False |
별칭이 있어도 필드명으로 값 설정 허용 |
serialize_by_alias |
bool |
False |
직렬화 시 별칭 사용 |
alias_generator |
Callable[[str], str] | None |
None |
별칭 자동 생성 함수 |
loc_by_alias |
bool |
True |
에러 위치에 별칭 사용 |
예시:
from pydantic import Field
class APIResponse(BaseModel):
model_config = ConfigDict(
validate_by_alias=True,
validate_by_name=True,
serialize_by_alias=True
)
user_name: str = Field(alias="userName")
# 둘 다 가능
response1 = APIResponse(userName="John")
response2 = APIResponse(user_name="John")
print(response1.model_dump(by_alias=True)) # {"userName": "John"}
예시 - alias_generator:
def to_camel(name: str) -> str:
parts = name.split('_')
return parts[0] + ''.join(word.capitalize() for word in parts[1:])
class CamelModel(BaseModel):
model_config = ConfigDict(
alias_generator=to_camel,
serialize_by_alias=True
)
first_name: str
last_name: str
data = CamelModel(firstName="John", lastName="Doe")
print(data.model_dump(by_alias=True))
# {"firstName": "John", "lastName": "Doe"}
JSON 스키마
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
title |
str | None |
None |
JSON 스키마 타이틀 |
json_schema_extra |
dict | Callable | None |
None |
JSON 스키마에 추가할 정보 |
json_schema_serialization_defaults_required |
bool |
False |
직렬화 스키마에서 기본값이 있는 필드도 required로 표시 |
json_schema_mode_override |
Literal['validation', 'serialization', None] |
None |
JSON 스키마 모드 강제 지정 |
예시 - json_schema_extra:
class Product(BaseModel):
model_config = ConfigDict(
title="상품 정보",
json_schema_extra={
"example": {
"name": "노트북",
"price": 1500000
},
"description": "상품 데이터를 나타내는 모델"
}
)
name: str
price: int
# OpenAPI/Swagger 문서에 예시가 표시됨
예시 - Callable json_schema_extra:
def add_examples(schema: dict) -> dict:
schema["examples"] = [
{"name": "예시1", "value": 100},
{"name": "예시2", "value": 200}
]
return schema
class DynamicSchema(BaseModel):
model_config = ConfigDict(json_schema_extra=add_examples)
name: str
value: int
ORM/속성 모드
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
from_attributes |
bool |
False |
객체 속성에서 모델 생성 허용 (SQLAlchemy 등) |
예시:
class UserORM:
def __init__(self, name: str, age: int):
self.name = name
self.age = age
class UserModel(BaseModel):
model_config = ConfigDict(from_attributes=True)
name: str
age: int
orm_user = UserORM(name="John", age=30)
pydantic_user = UserModel.model_validate(orm_user)
print(pydantic_user) # name='John' age=30
Enum 처리
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
use_enum_values |
bool |
False |
Enum 대신 값(value)으로 저장 |
예시:
from enum import Enum
class Status(Enum):
ACTIVE = "active"
INACTIVE = "inactive"
class User(BaseModel):
model_config = ConfigDict(use_enum_values=True)
status: Status
user = User(status=Status.ACTIVE)
print(user.status) # "active" (문자열)
print(type(user.status)) # <class 'str'>
# use_enum_values=False (기본값)이면
# user.status는 Status.ACTIVE (Enum 객체)
직렬화 설정
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
ser_json_timedelta |
'iso8601' | 'float' |
'iso8601' |
timedelta JSON 직렬화 형식 |
ser_json_bytes |
'utf8' | 'base64' | 'hex' |
'utf8' |
bytes JSON 직렬화 인코딩 |
ser_json_inf_nan |
'null' | 'constants' | 'strings' |
'null' |
무한대/NaN JSON 직렬화 형식 |
숫자/Float 설정
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
allow_inf_nan |
bool |
True |
float에서 무한대/NaN 허용 |
coerce_numbers_to_str |
bool |
False |
숫자를 문자열로 강제 변환 허용 |
기타 설정
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
protected_namespaces |
tuple[str, ...] |
('model_',) |
보호할 필드명 접두사 |
hide_input_in_errors |
bool |
False |
에러 메시지에서 입력값 숨김 |
defer_build |
bool |
False |
validator/serializer 빌드 지연 |
use_attribute_docstrings |
bool |
False |
속성 docstring을 필드 설명으로 사용 |
regex_engine |
'rust-regex' | 'python-re' |
'rust-regex' |
정규식 엔진 선택 |
validation_error_cause |
bool |
False |
Python 예외를 에러 원인에 포함 |
설정 상속
자식 모델은 부모 모델의 model_config를 상속받습니다.
class ParentModel(BaseModel):
model_config = ConfigDict(
str_strip_whitespace=True,
extra='allow'
)
name: str
class ChildModel(ParentModel):
model_config = ConfigDict(
frozen=True # 부모 설정 + frozen=True
)
age: int
# ChildModel은 str_strip_whitespace=True, extra='allow', frozen=True
FastAPI와 함께 사용
FastAPI에서 요청/응답 스키마로 사용할 때 특히 유용합니다.
from fastapi import FastAPI
from pydantic import BaseModel, ConfigDict, Field
app = FastAPI()
class CreateUserRequest(BaseModel):
model_config = ConfigDict(
str_strip_whitespace=True,
json_schema_extra={
"example": {
"username": "johndoe",
"email": "john@example.com"
}
}
)
username: str = Field(..., min_length=3, max_length=50)
email: str
class UserResponse(BaseModel):
model_config = ConfigDict(
from_attributes=True, # ORM 객체에서 변환 가능
serialize_by_alias=True
)
id: int
user_name: str = Field(alias="userName")
@app.post("/users", response_model=UserResponse)
async def create_user(user: CreateUserRequest):
# user.username은 자동으로 공백이 제거됨
...
주의사항
-
v1에서 마이그레이션:
class Config는 deprecated입니다.model_config = ConfigDict(...)를 사용하세요. -
populate_by_name은 deprecated:
validate_by_alias와validate_by_name을 함께 사용하세요. -
json_encoders는 deprecated: 커스텀 직렬화가 필요하면
@field_serializer데코레이터를 사용하세요.