ํฐ์คํ ๋ฆฌ ๋ทฐ
๐ฃ๏ธ Pydantic ์ ํ ์ด์
์์ฆ ๊ฐ์ AI ์๋์๋ ์คํฌ๋ฆฝํธ ์ธ์ด๋ ์ ์ ํ์ ์ ์ด์ฉํ์ฌ ๋ณด๋ค ๋ช ์์ ์ผ๋ก ์ฝ๋ฉํ๋ ค๋ ํ๋ฆ์ด ์๋ ๊ฒ ๊ฐ๋ค.
๋ช ์ธ๋ฅผ ๋ณด๋ค ๋ช ํํ ์์ฑํ๊ฑฐ๋ ํ ์คํธ๋ฅผ ์์ฑํ๋ ์ผ์ด ์์ ์ด๋ฉด ๋ณ๋ชฉ์ธ ์์ ์ด์๋ค๋ฉด,
์์๋ AI์ ๋์์ผ๋ก ๋ณด๋ค ์์ ์ ์ด๋ฉฐ ๋ ๋น ๋ฅด๊ฒ ๊ฐ๋ฐํ ์ ์๋ ์๋จ์ด ๋์๋ค.
์ด๋ฐ ํ๋ฆ์ ๋ง์ถฐ์ Javascript ์ง์์๋ Typescript,Python ์ง์์๋ Pydantic ์ธ๊ธฐ๊ฐ ๋ถ์ํ๊ฒ ์๋๊น ์ถ๋ค.
๊ทธ๋ฌ๋ฉด ์ด๋ค ๊ธฐ๋ฅ์ด ์๋์ง ํ ๋ฒ ์ ๋ฆฌํด๋ณด๋๋ก ํ์.
โ 1. ์๋ ๋ฐ์ดํฐ ํ์ฑ
๋จ์ํ ํ์ ์ฒดํฌ๋ฅผ ๋์ด, ์ ๋ ฅ๋ ๊ฐ์ ์ ์ธ๋ ํ์ ์ผ๋ก ๊ฐ์ ๋ณํ.
from pydantic import BaseModel
class Item(BaseModel):
id: int
name: str
price: float
is_available: bool
# ๋ฌธ์์ด "100"๊ณผ "4500.50", "true"๊ฐ ๋ค์ด์๋ ์๋์ผ๋ก ํ์ฑ๋ฉ๋๋ค.
external_data = {
"id": "100",
"name": "๋ชจ๋ํฐ",
"price": "4500.50",
"is_available": "true"
}
# Pylance ๊ฒฝ๊ณ ๊ฐ ๋ฐ์!
# item = Item(**external_data)
# model_validate๋ฅผ ์ด์ฉํด ๊ฒ์ฆ ๋ฐ ๋ณํ ์ํ
item = Item.model_validate(external_data)
print(item.id) # 100 (int)
print(item.price) # 4500.5 (float)
print(item.is_available) # True (bool)
- BaseModel ์์์ ํตํด์ Pydantic ๊ธฐ๋ฅ ์ฌ์ฉ.
- Pydantic์ ๊ธฐ๋ณธ ํด๋์ค์ด๋ฏ๋ก ํ์์ ์ผ๋ก ์์
- item = Item(**external_data) Dictinary Unpacking์ ์ฌ์ฉํ์ฌ๋ ๋์ง๋ง Pylance๋ฅผ ํตํด ์ฆ์ ๊ฒ์ฆ์ด Validation ์๋ฌ ๋ฐ์
- model_validate๋ฅผ ํตํด์ ๋ช ์์ ์ผ๋ก ๋ณํ๋ง ์งํํ๋๋ก ํ๋ค.

๐ model_validate ์ฌ์ฉ ์๊ธฐ
- ์์ ์์ ๋ก model_validate๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฒ์ฆ ๋์ ๋ณํ๋ง ๋ช ์์ ์ผ๋ก ์งํํ๋ค
- ์์ฒญ, ์๋ต๊ณผ ๊ฐ์ด ์ธํฐํ์ด์ค๋ฅผ ํตํ ๋ฐ์ดํฐ ์ , ์ถ๋ ฅ์ Pydantic Class ๊ทธ๋๋ก ์ฌ์ฉํ๋ค.
- ์ฝ๋๋จ์์ ์ง์ ๋ฐ์ดํฐ ๊ฐ๊ณตํ์ฌ ๊ฒ์ฆ์ด ์๋ฃ๋ ๋ฐ์ดํฐ์ธ ๊ฒฝ์ฐ์๋ model_validate ๋ฅผ ์ฌ์ฉํ์ฌ ๋ณํ๋ง ์ํํ๋ค
โ Camel ๋ณํ
์๋ฒ๋จ์์ ํํ ์ฌ์ฉํ๋ snake ↔ camel ๋ณํ์ด๋ค.
python convention์ ๋ฐ๋ผ ๋ด๋ถ์์๋ snake case๋ฅผ ์ฌ์ฉํ๊ณ ,
์ธํฐํ์ด์ค ์์์๋ camelCase ๋ฐ์ดํฐ๋ฅผ ์ก์์ ํ๋ ๊ฒฝ์ฐ ์ ์ฉํ๋ค.
def to_camel(value: str) -> str:
head, *tail = value.split("_")
return head + "".join(part.capitalize() for part in tail)
# CamelModel ์ ์
## alias_generator์ camel ๋ณํ ํจ์ ์ฐ๊ฒฐ
class CamelModel(BaseModel):
model_config = ConfigDict(
alias_generator=to_camel,
populate_by_name=True,
)
# CasemModel ์์
class ImgProcessingForm(CamelModel):
prc_type: PrcType
kernel_size: int | None = None\\
โ 2. ์ค์ฒฉ๋ ๋ชจ๋ธ
๋ณต์กํ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ฒด ์งํฅ์ ์ผ๋ก ์ ์ ๊ฐ๋ฅ.
from typing import List
class QuoteItem(BaseModel):
product_name: str
quantity: int
class Quote(BaseModel):
quote_id: str
vendor_name: str
items: List[QuoteItem] # ๋ค๋ฅธ Pydantic ๋ชจ๋ธ์ ๋ฆฌ์คํธ๋ก ํฌํจ
data = {
"quote_id": "Q-2026-001",
"vendor_name": "์ผ์ฑ์ ์",
"items": [
{"product_name": "๋
ธํธ๋ถ", "quantity": 5},
{"product_name": "๋ง์ฐ์ค", "quantity": 10}
]
}
quote = Quote(**data)
print(quote.items[0].product_name) # '๋
ธํธ๋ถ'
- ์์ฑ์ ๊ธฐ์กด ๋ชจ๋ธ์ ํ์ฉํด ๋ฐ์ดํฐ ๊ตฌ์กฐ ์ ์ (Quote.items)
โ 3. ์ปค์คํ ์ ํจ์ฑ ๊ฒ์ฌ
๊ธฐ๋ณธ ํ์ ์ธ์ ๋น์ฆ๋์ค ๋ก์ง(์: ์๋์ 0๋ณด๋ค ์ปค์ผ ํจ)์ ๊ฐ์ ํ ๋ ์ฌ์ฉ.
from pydantic import BaseModel, field_validator
class Inventory(BaseModel):
stock: int
@field_validator('stock')
@classmethod
def check_positive_stock(cls, v: int):
if v < 0:
raise ValueError('์ฌ๊ณ ๋ ์์์ผ ์ ์์ต๋๋ค.')
return v
# ์๋ฌ ๋ฐ์ ์์
try:
Inventory(stock=-5)
except ValueError as e:
print(e) # ์ฌ๊ณ ๋ ์์์ผ ์ ์์ต๋๋ค.
โ 4. ์ง๋ ฌํ (Serialization)
๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ๋ค์ JSON์ด๋ Dictionary๋ก ๋ณํํ์ฌ DB์ ์ ์ฅํ๊ฑฐ๋ API ์๋ต์ผ๋ก ๋ณด๋ผ ๋ ์ฌ์ฉ.
# Pydantic V2 ๊ธฐ์ค
quote_dict = quote.model_dump() # Python dict๋ก ๋ณํ
quote_json = quote.model_dump_json() # JSON ๋ฌธ์์ด๋ก ๋ณํ
print(type(quote_dict)) # <class 'dict'>
print(quote_json) # '{"quote_id":"Q-2026-001", ...}'
FastAPI์์๋ ๋ผ์ฐํฐ์์ BaseModel ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ฉด JSON ์คํค๋ง๋ก ์๋ ๋ณํ ๋จ.
class FileListResponse(BaseModel):
has_more: bool = Field(..., description="๋ค์ ํ์ด์ง ์กด์ฌ ์ฌ๋ถ")
next_cursor_uploaded_at: datetime | None = Field(None, description="๋ค์ ์ปค์ ๊ธฐ์ค ์
๋ก๋ ์๊ฐ")
next_cursor_id: str | None = Field(None, description="๋ค์ ์ปค์ ํ์ผ ID")
@router.get("/image-processing")
async def get_saved_images() {
...
return FileListResponse(...)
}
โ 5. ํ๊ฒฝ ์ค์ ๊ด๋ฆฌ
.env ํ์ผ์ด๋ ์์คํ ํ๊ฒฝ ๋ณ์๋ฅผ ์ฝ์ด์ฌ ๋ ์ ์ฉ.
BsseSettings ํด๋์ค๋ฅผ ์ด์ฉํ์ฌ ์ค์ ๊ตฌ์ฑ์ ํ๋ฉด ๋๋ค.
pydantic-settings ํจํค์ง๊ฐ ํ์ํ๋ฉฐ FastAPI ์ค์น ์ ๊ธฐ๋ณธ์ ์ผ๋ก ํฌํจ๋์ด ์๋ค.
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
app_name: str = "FastAPI Server"
env: str = "local"
debug: bool = True
api_prefix: str = "/api"
database_url: str = "postgresql://postgres:test1!@localhost:5434/postgres"
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
)
# .env ํ์ผ์ ํตํด์ ์ค์ ๋ ๊ฐ๋ฅ
# class Config:
# env_file = ".env"
settings = Settings()
๋ถ๋ก
OpenAPI
FastAPI์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก
Pydantic ๊ธฐ๋ฐ์ผ๋ก OpenAPI ์คํ์ ์์ฑํด์ฃผ๊ณ Swagger๋ฅผ ํตํด ํ์ธํ ์ ์๋ค.


๋ง๋ฌด๋ฆฌ
- python์ ์ปดํ์ผ ํ์์ ๊ฒ์ฆ ํ๊ธฐ ์ํด์๋ Pydantic์ด ํ์
- FastAPI์์๋ Pydantic ๊ธฐ๋ฐ OpenAPI ๋ช ์ธ ์๋ํ๊ฐ ๋์ด ์์ด ๋งค์ฐ ํธ๋ฆฌ
- ์์ ์ ์ด๊ณ AI๊ธฐ๋ฐ ๋น ๋ฅธ ๊ฐ๋ฐ์ ์ํด์๋ Pydantic์ ์ ํ์ด ์๋ ํ์.
'python' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [python] with ์ ๊ณผ contextmanager์ ๋ํด์ ์์๋ณด์ (0) | 2026.04.01 |
|---|---|
| [FastAPI] ์ด๊ธฐ ๊ตฌ์ฑ ๋ฐ ํจํค์ง ์ค์น (0) | 2026.02.25 |
| [Python] Jinja, Blueprint๋ฅผ ํ์ฉํด ์น ํ์ด์ง ์ปดํฌ๋ํธํ ํ๊ธฐ (0) | 2022.08.22 |
| [python] python -m pip install vs pip install (0) | 2022.08.18 |
| [Python] VS Code์ python ํ๊ฒฝ ๊ตฌ์ฑํ๊ธฐ (0) | 2022.08.16 |
- Total
- Today
- Yesterday
- docker mssql create database
- ์ค๋ธ์
- Composable vs Component
- Pydantic ๊ธฐ๋ฅ
- unmounted document.addlistener
- nuxt3 structure
- FastAPI ์ด๊ธฐ ๊ตฌ์ฑ
- vue watch ๋์ฒด
- vue watch ๋ฌธ์ ์
- Composable vs Class
- nuxt3 quasar ์ค์
- ์์กด์ฑ ํจํค์ง ๊ด๋ฆฌ
- ์ค๋งํธํผ์ฑ๋ณดํธ_์บ ํ์ธ
- ์ธ๋ํค ์ญ์
- docker mssql ์ด๋ฏธ์ง ์์ฑ
- nuxt3 ํ๋ก์ ํธ ์ค์
- oracle 19c ์ค์น
- ํฐ์คํ ๋ฆฌ์ฑ๋ฆฐ์ง
- nuxt3 eslint prettier ์ค์
- docker mssql
- Pydantic ๊ธฐ์ด
- Oracle Database 19C ์ค์น
- vue watch ์ํ์ฑ
- python Pydantic
- vue ๋ฆฌํฉํ ๋ง
- unplugin-auto-import
- python venv ๊ตฌ์ฑ
- Compoent
- Oracle Database 19c install
- ์คํ๋ฅดํ ์ฝ๋ฉํด๋ฝ
| ์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |

