In Pydantic, is it possible to pass a value that is not a dict and still make it go through a BaseModel?
I have a case where I want to be able to process a CIDR formatted IP (eg 1.2.3.4/32) and still return a valid model Ipv4.
In the example below I initialize 3 IPs. For the 3rd IP I pass a CIDR formatted str and want to be able to return a valid Ipv4 model.
the @root_validator is only used to print the passed values.
You can see that the 3rd value for key 'ip3' is not processed by the class. The error is
pydantic.error_wrappers.ValidationError: 1 validation error for Ips ip3
value is not a valid dict (type=type_error.dict)
from pydantic import BaseModel, root_validator
class Ipv4(BaseModel):
"""
Validate structure of IPv4
"""
address: str
subnet_mask: int = 22
@root_validator(pre=True)
def handle_address_from_cidr_notation(cls, values):
print(f'These are the values passed into the model: {values}')
return values
class Ips(BaseModel):
ip1: Ipv4
ip2: Ipv4
ip3: Ipv4
ips_dict = {
'ip1': {'address': '1.1.1.1', 'subnet_mask': 24},
'ip2': {'address': '1.1.1.1'},
'ip3': '1.1.1.1',
}
ips: Ips = Ips(**ips_dict)
print(ips.ip1)
print(ips.ip2)
print(ips.ip3)
These are the values passed into the model: {'address': '1.1.1.1', 'subnet_mask': 24}
These are the values passed into the model: {'address': '1.1.1.1'}
Traceback (most recent call last):
File "playground/test_pydantic_13.py", line 30, in <module>
ips: Ips = Ips(**ips_dict)
File "pydantic/main.py", line 406, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for Ips
ip3
value is not a valid dict (type=type_error.dict)
This works on Python 3.10 with pydantic 1.9 For Python 3.6 with pydantic 1.9, There is an error when using
Union[Ipv4, Ipv4Cidr]
Model Ipv4Cidr provides a validate method that splits the cidr formatted str to address and su.net_mask and passes the new values to Model Ipv4 which it inherits.
This allows for passing the IP in 3 different ways:
from typing import Optional, Union
from pydantic import BaseModel
class Ipv4(BaseModel):
"""
Validate structure of IPv4
"""
address: str
subnet_mask: Optional[int]
class Ipv4Cidr(Ipv4):
"""
Validate structure of IPv4
"""
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, value: str, field):
if isinstance(value, str):
try:
address, subnet_mask = value.split('/')
return Ipv4(address=address, subnet_mask=subnet_mask)
except ValueError as ve:
return Ipv4(address=value)
else:
return Ipv4(**value)
class Ips(BaseModel):
ip1: Ipv4
ip2: Union[Ipv4, Ipv4Cidr]
ip3: Ipv4Cidr
ip4: Union[Ipv4, Ipv4Cidr]
ips_dict = {
'ip1': {'address': '1.1.1.1', 'subnet_mask': 24},
'ip2': {'address': '2.2.2.2'},
'ip3': '3.3.3.3/32',
'ip4': '4.4.4.4/32',
}
ips: Ips = Ips(**ips_dict)
print(ips.ip1)
print(ips.ip2)
print(ips.ip3)
print(ips.ip4)
address='1.1.1.1' subnet_mask=24
address='2.2.2.2' subnet_mask=None
address='3.3.3.3' subnet_mask=32
address='4.4.4.4' subnet_mask=32
Traceback (most recent call last):
File "playground/test_pydantic_13.py", line 50, in <module>
ips: Ips = Ips(**ips_dict)
File "pydantic/main.py", line 331, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for Ips
ip4
value is not a valid dict (type=type_error.dict)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.