Как в pydantic проверять наличие нужных полей и отсутствие лишних?
Подскажите пожалуйста, как проверять наличие лишних или отсутствие обязательных полей с помощью pydantic?
В библиотеке dataclasses это делает очень просто:
from dataclasses import dataclass, field
@dataclass
class Children:
type_name: str
type_id: int
disabled: bool
children: List[str]
# Данные с полем id >>> TypeError: Children.__init__() got an unexpected keyword argument 'id'
# Данные без поля type_name >>> TypeError: Children.__init__() missing 1 required positional argument: 'type_name'
Если в какое-то из полей в полученных данных будут отсутствовать то вернется исключение TypeError, сообщив, что есть лишний аргумент или отсутствует обязательный.
Однако в pydantic такого поведения я не наблюдаю, если в данных не будет поля, то он просто провалидирует имеющиеся, а если будут лишние, то не сообщит об этом и вернет только те поля, что есть в Pydantic
class ApiResponseModel(BaseModel):
data: Optional[Any] = Field(default=None)
count_rows: Optional[int] = Field(default=0)
request_date: Optional[datetime] = Field(default=datetime.utcnow())
requests_count: int = Field(default_factory=int)
api_type: Optional[str] = Field(default=None)
def __init__(self, **data):
super().__init__(**data)
self.count_rows = len(self.data)
class Warehouses(ApiResponseModel):
schedule: Dict = Field(default_factory=dict)
warehouse: Dict = Field(default_factory=dict)
def __init__(self, **data):
super().__init__(**data)
# Данные с полем без поля schedule после валидации просто вернуться с пустым словарём
# Если добавить в модель еще поле, то в ответе будет дополнительно это поле.
Таким образом pydantic нативно не проверяет наличие обязательных полей, но скорее всего я делаю что-то не так, так как это можно решить у pydantic?
Ответы (1 шт):
Смотрим ваш код:
class Warehouses(ApiResponseModel):
schedule: Dict = Field(default_factory=dict)
warehouse: Dict = Field(default_factory=dict)
def __init__(self, **data):
super().__init__(**data)
Ниже вы пишете
Данные с полем без поля schedule после валидации просто вернуться с пустым словарём
Смотрим код, видим default_factory
. Параметр default_factory
- это указание, какая функция будет вызвана, чтобы сгенерировать значение по умолчанию при отсутствии поля. Т.е. буквально у вас в коде написано, что если поля нет, то будет вызвана функция dict, и поле заполнится новым пустым словарем.
Если убрать default_factory
, тогда будет падать с ошибкой валидации, если поле не будет передано:
from pydantic import BaseModel
from typing import Dict
class Warehouses(BaseModel):
schedule: Dict
warehouse: Dict
warehouses = Warehouses()
Вывод:
File "/home/insolor/Projects/test.py", line 10, in <module>
warehouses = Warehouses()
File "/home/insolor/.local/lib/python3.10/site-packages/pydantic/main.py", line 165, in __init__
__pydantic_self__.__pydantic_validator__.validate_python(data, self_instance=__pydantic_self__)
pydantic_core._pydantic_core.ValidationError: 2 validation errors for Warehouses
schedule
Field required [type=missing, input_value={}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.3/v/missing
warehouse
Field required [type=missing, input_value={}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.3/v/missing
Чтобы не игнорировались лишние поля, добавляете настройку
model_config = ConfigDict(extra="forbid")
:
from pydantic import BaseModel, ConfigDict
from typing import Dict
class Warehouses(BaseModel):
model_config = ConfigDict(extra="forbid")
schedule: Dict
warehouse: Dict
warehouses = Warehouses(schedule={}, warehouse={}, sdfwef=10)
Вывод:
Traceback (most recent call last):
File "/home/insolor/Projects/test.py", line 11, in <module>
warehouses = Warehouses(sdfwef=10)
File "/home/insolor/.local/lib/python3.10/site-packages/pydantic/main.py", line 165, in __init__
__pydantic_self__.__pydantic_validator__.validate_python(data, self_instance=__pydantic_self__)
pydantic_core._pydantic_core.ValidationError: 1 validation error for Warehouses
sdfwef
Extra inputs are not permitted [type=extra_forbidden, input_value=10, input_type=int]
For further information visit https://errors.pydantic.dev/2.3/v/extra_forbidden
Решение для Pydantic 2.*, взято отсюда: Pydantic validations for extra fields that not defined in schema