[英]How to validate more than one field of pydantic model
我想验证 pydantic model 的三个 model 字段。 为此,我从 pydantic 导入 root_validator。 低于错误。 我在https://pydantic-docs.helpmanual.io/usage/validators/#root-validators中找到了这个。 任何人都可以帮助我。 找出下面的错误。 from pydantic import BaseModel, ValidationError, root_validator Traceback(最近一次调用最后一次):文件“”,第 1 行,在 ImportError 中:无法从“pydantic”导入名称“root_validator”(C:\Users\Lenovo\AppData\Local\Programs\ Python\Python38-32\lib\site-packages\pydantic__init__.py)
我试过了
@validator
def validate_all(cls,v,values,**kwargs):
我从一些常见的字段父 model 继承了我的 pydantic model。 值仅显示父 class 字段,但不显示我的子 class 字段。 例如
class Parent(BaseModel):
name: str
comments: str
class Customer(Parent):
address: str
phone: str
@validator
def validate_all(cls,v,values, **kwargs):
#here values showing only (name and comment) but not address and phone.
您需要将字段作为装饰器的 arguments 传递。
class Parent(BaseModel):
name: str
comments: str
class Customer(Parent):
address: str
phone: str
@validator("name", "coments", "address", "phone")
def validate_all(cls, v, values, **kwargs):
首先,如果您在导入root_validator时出错,我会更新 pydantic。
pip install -U pydantic
上面的许多示例向您展示了如何一次对多个值使用相同的验证器。 或者他们增加了很多不必要的复杂性来完成你想要的。 您可以简单地使用以下代码,使用root_validator装饰器在同一个验证器中同时验证多个字段:
from pydantic import root_validator
from pydantic import BaseModel
class Parent(BaseModel):
name: str = "Peter"
comments: str = "Pydantic User"
class Customer(Parent):
address: str = "Home"
phone: str = "117"
@root_validator
def validate_all(cls, values):
print(f"{values}")
values["phone"] = "111-111-1111"
values["address"] = "1111 Pydantic Lane"
print(f"{values}")
return values
Output:
{'name': 'Peter', 'comments': 'Pydantic User', 'address': 'Home', 'phone': '117'}
{'name': 'Peter', 'comments': 'Pydantic User', 'address': '1111 Pydantic Lane', 'phone': '111-111-1111'}
为了扩展Rahul R
的答案,这个例子更详细地展示了如何使用pydantic
验证器。
此示例包含回答您的问题所需的所有信息。
import pydantic
class Parent(pydantic.BaseModel):
name: str
comments: str
class Customer(Parent):
address: str
phone: str
# If you want to apply the Validator to the fields "name", "comments", "address", "phone"
@pydantic.validator("name", "comments", "address", "phone")
@classmethod
def validate_all_fields_one_by_one(cls, field_value):
# Do the validation instead of printing
print(f"{cls}: Field value {field_value}")
return field_value # this is the value written to the class field
# if you want to validate to content of "phone" using the other fields of the Parent and Child class
@pydantic.validator("phone")
@classmethod
def validate_one_field_using_the_others(cls, field_value, values, field, config):
parent_class_name = values["name"]
parent_class_address = values["address"] # works because "address" is already validated once we validate "phone"
# Do the validation instead of printing
print(f"{field_value} is the {field.name} of {parent_class_name}")
return field_value
Customer(name="Peter", comments="Pydantic User", address="Home", phone="117")
Output
<class '__main__.Customer'>: Field value Peter
<class '__main__.Customer'>: Field value Pydantic User
<class '__main__.Customer'>: Field value Home
<class '__main__.Customer'>: Field value 117
117 is the phone number of Peter
Customer(name='Peter', comments='Pydantic User', address='Home', phone='117')
要更详细地回答您的问题:
将要验证的字段添加到验证@validator
正上方的 @validator 装饰器。
@validator("name")
使用 " "name"
" 的字段值(例如"Peter"
)作为验证 function 的输入。 class 及其父类的所有字段都可以添加到@validator
装饰器中。validate_all_fields_one_by_one
) 然后使用字段值作为第二个参数 ( field_value
) 来验证输入。 验证 function 的返回值写入 class 字段。 验证 function 的签名是def validate_something(cls, field_value)
其中 function 和变量名称可以任意选择(但第一个参数应该是cls
)。 根据 Arjan ( https://youtu.be/Vj-iU-8_xLs?t=329 ),还应该添加@classmethod
装饰器。 如果目标是通过使用父子 class 的其他(已验证)字段来验证一个字段,则验证 function 的完整签名是def validate_something(cls, field_value, values, field, config)
(参数名称values
, field
和config
必须匹配)可以使用字段名称作为键访问字段的值(例如values["comments"]
)。
此示例包含回答您的问题所需的所有信息。
class User(BaseModel):
name: Optional[str] = ""
class Config:
validate_assignment = True
@validator("name")
def set_name(cls, name):
return name or "foo"
根据文档,“可以通过传递多个字段名称将单个validator
应用于多个字段”(并且“也可以通过传递特殊值'*'
在所有字段上调用”)。 因此,您可以将希望验证的字段添加到validator
装饰器,并使用field.name
属性,您可以检查每次调用validator
器时要验证的字段。 如果一个字段没有通过验证,您可以raise ValueError
,“这将被捕获并用于填充ValidationError
”(请参阅此处的“注意”部分)。 如果您需要根据其他字段验证字段,则必须首先检查它们是否已经使用values.get()
方法进行了验证,如本答案所示(更新 2) 。 下面演示了一个示例,其中验证了name
、 country_code
和phone
号码等字段(基于提供的country_code
)。 提供的正则表达式模式只是本演示的示例,并且基于这个和这个答案..
from pydantic import BaseModel, validator
import re
name_pattern = re.compile(r'[a-zA-Z\s]+$')
country_codes = {"uk", "us"}
UK_phone_pattern = re.compile(r'^(\+44\s?7\d{3}|\(?07\d{3}\)?)\s?\d{3}\s?\d{3}$') # UK mobile phone number. Valid example: +44 7222 555 555
US_phone_pattern = re.compile(r'^(\([0-9]{3}\) |[0-9]{3}-)[0-9]{3}-[0-9]{4}$') # US phone number. Valid example: (123) 123-1234
phone_patterns = {"uk": UK_phone_pattern, "us": US_phone_pattern}
class Parent(BaseModel):
name: str
comments: str
class Customer(Parent):
address: str
country_code: str
phone: str
@validator("name", "country_code", "phone")
def validate_atts(cls, v, values, field):
if field.name == "name":
if not name_pattern.match(v): raise ValueError(f'{v}" is not a valid name.')
elif field.name == "country_code":
if not v.lower() in country_codes: raise ValueError(f'{v} is not a valid country code.')
elif field.name == "phone" and values.get('country_code'):
c_code = values.get('country_code').lower()
if not phone_patterns[c_code].match(v): raise ValueError(f'{v} is not a valid phone number.')
return v
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.