[TIL] pydantic v2 (유데미)
fastapi 를 공부하다 보니 익숙하지 않은 Annotated[] 와 같은 구문이 매우 거슬렸습니다.
그러던 와중에 API request 클래스가 pydantic의 BaseModel 을 상속받는 부분에서 사전공부가 부족한 걸 느꼈습니다.
파이썬 2.7과 3.2가 경합하던 시절에 공부를 했는데, 요즘 파이썬 문법은 현란하게 달라져 있단 걸 알게 되었네요.
(validation 라이브러리로서만이 아니라 파이썬 문법에 대한 공부를 위해서도 pydantic이 유용합니다)
pydantic 부터 공부하자고 생각해서 강의를 들었습니다.
https://www.udemy.com/course/pydantic/
5000명 이상이 수강했음에도 평점이 4.9로 최상급인 강의입니다.
단계적으로 pydantic 구문을 설명하면서 다음과 같은 클래스의 세세한 부분을 모두 이해하게 합니다.
from datetime import date
from enum import Enum
from functools import cached_property
from typing import Annotated, TypeVar
from uuid import uuid4
from pydantic import (
AfterValidator,
BaseModel,
ConfigDict,
computed_field,
Field,
field_serializer,
field_validator,
PlainSerializer,
UUID4,
ValidationInfo,
)
from pydantic.alias_generators import to_camel
class AutomobileType(Enum):
sedan = "Sedan"
coupe = "Coupe"
convertible = "Convertible"
suv = "SUV"
truck = "Truck"
T = TypeVar('T')
BoundedString = Annotated[str, Field(min_length=2, max_length=50)]
BoundedList = Annotated[list[T], Field(min_length=1, max_length=5)]
Country = Annotated[str, AfterValidator(lambda name: lookup_country(name)[0])]
def serialize_date(value: date) -> str:
return value.strftime("%Y/%m/%d")
CustomDate = Annotated[
date,
PlainSerializer(serialize_date, when_used="json-unless-none")
]
class Automobile(BaseModel):
model_config = ConfigDict(
extra="forbid",
str_strip_whitespace=True,
validate_default=True,
validate_assignment=True,
alias_generator=to_camel,
)
id_: UUID4 | None = Field(alias="id", default_factory=uuid4)
manufacturer: BoundedString
series_name: BoundedString
type_: AutomobileType = Field(alias="type")
is_electric: bool = Field(default=False, repr=False)
manufactured_date: CustomDate = Field(
validation_alias="completionDate",
ge=date(1980, 1, 1),
repr=False
)
base_msrp_usd: float = Field(
validation_alias="msrpUSD",
serialization_alias="baseMSRPUSD",
repr=False,
)
top_features: BoundedList[BoundedString] | None = Field(default=None, repr=False)
vin: BoundedString = Field(repr=False)
number_of_doors: int = Field(
default=4,
validation_alias="doors",
ge=2,
le=4,
multiple_of=2,
repr=False,
)
registration_country: Country | None = Field(default=None, repr=False)
@computed_field(repr=False)
@cached_property
def registration_country_code(self) -> str:
return country_code_lookup[self.registration_country]
registration_date: CustomDate | None = Field(default=None, repr=False)
license_plate: BoundedString | None = Field(default=None, repr=False)
@field_validator("registration_date")
@classmethod
def validate_registration_date(cls, value:date, values: ValidationInfo):
data = values.data
if "manufactured_date" in data and data["manufactured_date"] > value:
raise ValueError("Automobile cannot be registered prior to manufacture date.")
return value접어 두었던 fastapi 코드를 다시 보니 뭐가 뭔지 이해하기가 훨씬 쉬워졌습니다.
python / fastapi 강의로서 추천합니다.
