들어가기 전
Pydantic은 Python 영역에서 사용하는 타입 힌트와 데이터 검증을 보다 쉽고 명확하게 해주는 라이브러리이다. 누군가는 이러한 "타입을 강제하는 Pydantic이 Python을 Python스럽지 못하게 사용하는 것"이라 이야기하기도한다. 하지만 타입을 강제하는 것은 Python의 철학와는 별개로 서비스 운영측면에서 중요한 요소이다.
- 타입힌팅은 코드의 명확성을 높여주며, 개발자의 개발 생산성과 밀접한 연관이 있는 IDE의 자동완성 기능와 결합되어 높은 개발 생산성을 이끌어 낼 수 있다.
- 데이터 구조가 명확해짐으로써 다른 서비스팀와의 협업과 유지보수가 더욱 더 편리해진다.
Pydantic은 타입을 강제하는 것 뿐만아니라, 커스텀 유효성 검사와 데이터 직렬화(serialization) 및 역직렬화(deserialization)을 지원한다.이를 통해 외부 데이터 소스와의 상호작용이 훨씬 더 용이하게 만든다.
나는 무엇보다도 서비스의 안정성과 유지보수성 측면에서 Pydantic을 사용하는 것을 선호한다. 그러나 이것이 Pydantic을 잘 안다는 것을 의미하는 것은 아니다. 그래서 Pydantic을 보다 잘 사용하기 위해 기초부터, 응용까지 기록을 해보고자 한다.
환경 설정
- python: 3.11.3
- pyadantic: 2.7.1
- pydantic_core: 2.18.2
Pydantic의 BaseModel 사용하기
Pydantic 모델 정의
우선, BaseModel을 상속하여 Pydantic 모델을 정의한다.
- Pydantic 모델은 상속하여, 속성과 메서드를 추가한 개념으로 이해한다.
- 선언한 각 필드에는 required=True 가 기본값으로 설정되어, 필수 필드로 간주된다.(필드 값을 선언하지 않을경우 ValidationError가 발생한다.)
- dict 또는 JSON 문자열을 통해 모델을 생성할 수 있다.
from pydantic import BaseModel
class Person(BaseModel):
first_name: str
last_name: str
age: int
p = Person(first_name='Seongyeon', last_name='Kim', age=29)
print(repr(p)) # 출력: Person(first_name='John', last_name='Doe', age=30)
print(p.model_fields) # 출력: {'first_name': ModelField(name='first_name', type=str, required=True), 'last_name': ModelField(name='last_name', type=str, required=True), 'age': ModelField(name='age', type=int, required=True)}
print(p.first_name) # 출력: Seongyeon
# ValidationError: 데이터 형식이 올바르지 않을 경우, 에러가 발생한다.
try:
Person(last_name='Error Seongyeon', age=29)
except ValidationError as ex:
print(ex)
"""
출력:
1 validation error for Person
first_name
Field required [type=missing, input_value={'last_name': 'Error Seongyeon', 'age': 29}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.7/v/missing
"""
주의 사항
기본 BaseModel을 사용할 경우(Config 설정이 없을 경우), 모델을 생성한 이후, 값을 새롭게 할당할 때 Validate가 진행되지 않는다.
class Person(BaseModel): first_name: str last_name: str age: int p = Person(first_name='Seongyeon', last_name='Kim', age=29) p.age = "twenty" # 에러가 발생하지 않음
1. dict를 사용하여 모델 생성하기
dict를 사용하여 Pydantic 모델을 생성하는 방법에는 두 가지가 있다.
- ** (언패킹 연산자)를 사용하는 방법
- model_validate() 메서드를 사용하는 방법
1.1. 언패킹 연산자(**)를 사용하여 모델 생성
dict_data = {
'first_name': 'Seongyeon',
'last_name': 'Kim',
'age': 29
}
deserializing_by_dict_p_1 = Person(**dict_data)
print(repr(deserializing_by_dict_p_1)) # 출력: Person(first_name='Seongyeon', last_name='Kim', age=29)
1.2. model_validate() 메서드를 사용하여 모델 생성
deserializing_by_dict_p_2 = Person.model_validate(dict_data)
print(repr(deserializing_by_dict_p_2)) # 출력: Person(first_name='Seongyeon', last_name='Kim', age=29)
2. JSON 문자열을 사용하여 모델 생성하기
JSON 문자열을 사용하여 Pydantic 모델을 생성하는 경우에는 `model_validate_json()` 메서드를 사용할 수 있다. 이는 주로 REST API 요청을 처리할 때 특히 유용 하다.
- 통신 JSON 데이터를 바로 Pydantic 모델로 생성할 수 있다.
json_data = '''
{
"first_name": "Seongyeon",
"last_name": "Kim",
"age": 29
}
'''
deserializing_by_json_p = Person.model_validate_json(json_data)
print(repr(deserializing_by_json_p_1)) # 출력: Person(first_name='Seongyeon', last_name='Kim', age=29)
# ValidationError: JSON 데이터 형식이 올바르지 않을 경우, 에러가 발생한다.
missing_data_json = '''
{
"last_name": "Wrong Kim"
}
'''
try:
Person.model_validate_json(missing_data_json)
except ValidationError as ex:
print(ex)
"""
2 validation errors for Person
first_name
Field required [type=missing, input_value={'last_name': 'Newton'}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.7/v/missing
age
Field required [type=missing, input_value={'last_name': 'Newton'}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.7/v/missing
"""
요약
Pydantic을 사용하면 dict와 JSON 문자열을 사용하여 간편하게 모델을 생성할 수 있다. dict를 사용할 경우에는 언패킹 연산자(**)와 model_validate() 메서드를, JSON 문자열을 사용할 경우에는 model_validate_json() 메서드를 사용한다. 이를 통해 효율적으로 데이터를 유효성 검사하고 관리할 수 있다.
참고자료
Welcome to Pydantic - Pydantic
Pydantic Documentation for version: v2.7.1. Pydantic is the most widely used data validation library for Python. Fast and extensible, Pydantic plays nicely with your linters/IDE/brain. Define how data should be in pure, canonical Python 3.8+; validate it w
docs.pydantic.dev
'개인공부' 카테고리의 다른 글
[ Django ] 유저 모델을 설계할 때, User, AbstractBaseUser, AbstractUser 중 어떤 클래스를 사용해야 할까? (0) | 2024.11.10 |
---|---|
[ Pydantic ] Pydantic을 활용한 Serialization(직렬화)와 Deserialization(역직렬화) (0) | 2024.05.30 |
[ JPA ] 다양한 어노테이션을 사용한 효과적인 엔터티 매핑_2.연관관계 매핑 (0) | 2024.02.12 |
[ JPA ] 다양한 어노테이션을 사용한 효과적인 엔터티 매핑_1.객체와 테이블 매핑 (0) | 2024.02.12 |
[ JPA ] JPA Entity, EntityManagerFactory, EntityManager, Persistence context (0) | 2024.02.11 |