Python

pydantic 모델 파싱시 비어있는 필드에 대해

Prower 2022. 8. 7. 01:32
728x90
반응형

pydantic 모델 파싱시 주의 사항

  • request나 response로 넘어온 body data를 pydantic이 model로 파싱하는 과정에서 정의된 필드가 비어있는 경우 에러를 던진다.

에러가 발생하는 예시

from pydantic import BaseModel
​
class Foo(BaseModel):
    id: int
    name: str
​
def service_method() -> dict:
    return { "name": "testing" }
​
def controller_method() -> Foo:
    result = service_method()
    return Foo(**result)
​
controller_method()
  • pydantic은 모델로 데이터를 파싱하는 과정에서 파싱이 불가능한 값이 들어온 경우 에러를 던진다.
  • 위 경우에서 Foo 모델은 반드시 int형의 idstring형의 name 필드가 존재해야 하며, 이를 만족하지 못하는 경우 에러를 던진다.

None에 대해 간과한 점

  • python에서 None은 값일 뿐 아니라 독립적인 type으로도 구분이 된다.
  • dictionary에서 빈값은 None type으로 처리된다. 즉, 위 경우에서 id 필드가 포함되지 않은 값은 pydantic이 파싱하는 과정에서 None 타입으로 인식하고 int 형이 아니기 때문에 에러를 던졌다고 이해할 수 있다.
  • 결국 위에서 정의한 모델은 Optional 조건을 추가하거나 None 타입을 허용하게 하여 다음과 같이 수정해야 한다.
class Foo(BaseModel):
    # Optional 사용
    id: Optional[int]
    # Union으로 타입 지정
    id: Union[int, None]
    name: str
  • 이렇게 하면 id 필드가 포함되지 않는 경우에도 에러를 던지지 않고 파싱이 가능해진다.

모델에 대한 정확한 정의

  • pydantic이 지정한 타입을 보장해 주는 역할을 한다고 했는데, 위 상황에서 pydantic이 에러를 던지지 않고 필드를 빈값으로 처리해 진행한다면 오히려 정확한 기능을 제공하지 않는 것으로 볼 수 있다.
    • id가 int형이 아닌 None 타입이 되므로
  • id
  • 결국 위와 같은 문제를 겪지 않으려면 통신 과정에서 정확한 모델에 대한 정의가 필요하고, 이를 강제로 지킬 수 있도록 하는게 중요할 것 같다.

Response 처리

  • response를 처리하는 과정에서 None 값을 가진 필드를 제외하고 반환하고자 하는 경우 다음과 같이 처리할 수 있다.

인스턴스를 json으로 변환하는 과정에서 제외

def controller_method() -> Foo:
    result = service_method()
    return Foo(**result).json(exclude_none=True)
​
print(controller_method())
​
> {'name': 'testing'}
  • fastapi의 controller단에서 response_model 로 설정한 경우 response_model_exclude_none 옵션을 통해 None 값을 제외시킬 수 있다.

response_model_exclude_none 옵션 설정

@app.get("/foo", response_model=Foo, response_model_exclude_none=True)
def controller_method() -> Foo:
    result = service_method()
    return Foo(**result).json(exclude_none=True)

 

728x90
반응형