Fast API Pydantic을 이용한 Type Hinting

Junha Kim·2021년 1월 3일
2

FastAPI

목록 보기
3/16
post-custom-banner

Pydantic

기존의 Flask나 Django와는 달리 Fast API는 Type Hints를 사용하고 있다.

Type Hints는 파라미터 값이 어떤 자료형이 들어와야하는 지 코드 상에서 명시하는 것이다.

아래의 예를 보자.

from pydantic import BaseModel
from typing import Optional

class User(BaseModel):
    id: int
    name = 'Jane Doe'
		age : Optional[str] = None

pydanticBaseModel을 상속받은 User 클래스에 id 필드를 int 형식으로, name은 Default 값으로 'Jane Doe'를 주어 type annotation이 불필요하다.

user = User(id='123')
assert user.id == 123 # Valid

Parsing Library, Not for data Validation

여기서 중요한 점은 Pydantic은 Parsing을 도와주는 것일 뿐, Validation Check을 하기 위한 라이브러리는 아니라는 것이다.

좀 더 직관적인 이해를 위한 코드를 보자.

from pydantic import BaseModel

class Model(BaseModel):
    a: int
    b: float
    c: str

print(Model(a=3.1415, b=' 2.72 ', c=123).dict())
#> {'a': 3, 'b': 2.72, 'c': '123'}

print(Model(a=3.1415, **b=' asd '**, c=123).dict())
'''
pydantic.error_wrappers.ValidationError: 1 validation error for Model
b
  value is not a valid float (type=type_error.float)
'''

위에서 볼 수 있 듯이, b의 값이 str으로 들어와도 이를 float으로 Parsing 해둔다는 것이다. 하지만 만약 Parsing이 불가능한 데이터 형식이 들어왔을 때는 Validation errorraise한다.


Model Recursion

데이터 형식을 명시하는 Pydantic은 사용자가 정의한 클래스 또한 annotation을 할 수 있다.

from typing import List
from pydantic import BaseModel

class Foo(BaseModel):
    count: int
    size: float = None

class Bar(BaseModel):
    apple = 'x'
    banana = 'y'

class Spam(BaseModel):
    foo: **Foo**
    bars: **List[Bar]**

m = Spam(foo={'count': 4}, bars=[{'apple': 'x1'}, {'apple': 'x2'}])
print(m)
#> foo=Foo(count=4, size=None) bars=[Bar(apple='x1', banana='y'),
#> Bar(apple='x2', banana='y')]
print(m.dict())
"""
{
    'foo': {'count': 4, 'size': None},
    'bars': [
        {'apple': 'x1', 'banana': 'y'},
        {'apple': 'x2', 'banana': 'y'},
    ],
}
"""

Other Examples

class User(BaseModel):
    id: int
    name = "John Doe"
    signup_ts: Optional[datetime] = None
    friends: List[int] = []

external_data = {
    "id": "123",
    "signup_ts": "2017-06-01 12:22",
    "friends": [1, "2", b"3"],
}
user = User(**external_data)
from typing import Set, Tuple

def process_items(items_t: Tuple[int, int, str], items_s: Set[bytes]):
  # items_t : int, int, str / 총 3개로 이루어진 튜플
	# items_s : byte로 이루어진 set
	return items_t, items_s

from typing import Dict

def process_items(prices: Dict[str, float]):
		# key는 str, value는 float
    for item_name, item_price in prices.items():
        print(item_name)
        print(item_price)

class Person:
    def __init__(self, name: str):
        self.name = name

def get_person_name(one_person: Person):
    return one_person.name
post-custom-banner

0개의 댓글