在Pydantic中,是否可以传递一个值而不是字典还能让它通过BaseModel吗?
我有一个情况,我希望能够处理一个CIDR格式的IP(例如1.2.3.4/32),仍然返回一个有效的模型Ipv4。
在下面的例子中,我初始化了3个ip。对于第三个IP,我传递一个CIDR格式的str,并希望能够返回一个有效的Ipv4模型。
@root_validator只用于打印传递的值。
可以看到键'ip3'的第三个值没有被类处理。错误是
pydantic.error_wrappers。ValidationError: 1个ip验证错误ip3
value不是一个有效的字典(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)
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)
此操作适用于Python 3.10和pydantic 1.9对于Python 3.6和pydantic 1.9,使用
时会出现错误Union[Ipv4, Ipv4Cidr]
Model Ipv4Cidr提供了一个验证方法,该方法将cidr格式的str拆分为address和subnet_mask,并将新值传递给它继承的Model Ipv4。
允许以三种不同的方式传递IP:
- ip地址+子网掩码 只有
- ip地址
- ip地址/子网掩码- cidr符号
代码
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)
Python 3.10 + Pydantic 1.9的输出
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
Python 3.6 + Pydantic 1.9的输出
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)