sam*_*mba 5 python validation pydantic
我想验证pydantic模型的三个模型字段。为此,我正在从 pydantic 导入 root_validator。低于错误。我在https://pydantic-docs.helpmanual.io/usage/validators/#root-validators 中找到了这个。任何人都可以帮助我。找出下面的错误。from pydantic import BaseModel, ValidationError, root_validator Traceback (最近一次调用): File "", line 1, in ImportError: cannot import name 'root_validator' from 'pydantic' (C:\Users\Lenovo\AppData\Local\Programs\ Python\Python38-32\lib\site-packages\pydantic__init__.py)
我试过
@validator
def validate_all(cls,v,values,**kwargs):
Run Code Online (Sandbox Code Playgroud)
我从一些常见的字段父模型继承了我的 pydantic 模型。仅显示父类字段的值,但不显示我的子类字段。例如
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.
Run Code Online (Sandbox Code Playgroud)
wue*_*eli 41
为了扩展 的答案Rahul R,此示例更详细地展示了如何使用pydantic验证器。
此示例包含回答您的问题的所有必要信息。
请注意,还可以选择使用 a @root_validator,如 所提到的Kentgrav,请参阅帖子底部的示例以了解更多详细信息。
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")
Run Code Online (Sandbox Code Playgroud)
输出
<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')
Run Code Online (Sandbox Code Playgroud)
更详细地回答您的问题:
将要验证的字段添加到@validator验证函数正上方的装饰器中。
@validator("name")"name"使用(eg )的字段值"Peter"作为验证函数的输入。类及其父类的所有字段都可以添加到@validator装饰器中。validate_all_fields_one_by_one) 使用字段值作为第二个参数 ( field_value) 来验证输入。验证函数的返回值写入类字段。验证函数的签名是def validate_something(cls, field_value)可以任意选择函数和变量名称的地方(但第一个参数应该是cls)。根据 Arjan ( https://youtu.be/Vj-iU-8_xLs?t=329 ) 的说法,还@classmethod应该添加装饰器。如果目标是使用父类和子类的其他(已验证)字段来验证一个字段,则验证函数的完整签名是def validate_something(cls, field_value, values, field, config)(参数名称values,field并且config 必须匹配),可以使用以下方式访问字段的值字段名称作为键(例如values["comments"])。
Edit1:如果您只想检查某种类型的输入值,您可以使用以下结构:
<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')
Run Code Online (Sandbox Code Playgroud)
Edit2:使用以下方法一起验证所有字段的更简单方法@root_validator:
@validator("*") # validates all fields
def validate_if_float(cls, value):
if isinstance(value, float):
# do validation here
return value
Run Code Online (Sandbox Code Playgroud)
输出:
import pydantic
class Parent(pydantic.BaseModel):
name: str
comments: str
class Customer(Parent):
address: str
phone: str
@pydantic.root_validator()
@classmethod
def validate_all_fields_at_the_same_time(cls, field_values):
# Do the validation instead of printing
print(f"{cls}: Field values are: {field_values}")
assert field_values["name"] != "invalid_name", f"Name `{field_values['name']}` not allowed."
return field_values
Run Code Online (Sandbox Code Playgroud)
Customer(name="valid_name", comments="", address="Street 7", phone="079")
<class '__main__.Customer'>: Field values are: {'name': 'valid_name', 'comments': '', 'address': 'Street 7', 'phone': '079'}
Customer(name='valid_name', comments='', address='Street 7', phone='079')
Run Code Online (Sandbox Code Playgroud)
小智 11
您需要将字段作为装饰器的参数传递。
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):
Run Code Online (Sandbox Code Playgroud)
@validator装饰器根据文档,“通过传递多个字段名称,可以将单个字段validator应用于多个字段”(并且“也可以通过传递特殊值在所有\'*\'字段上调用”)。因此,您可以将想要验证的字段添加到validator装饰器中,并使用field.name属性您可以检查每次validator调用时要验证哪个字段。如果某个字段未通过验证,您可以raise ValueError“将捕获并用于填充”(请参阅此处的ValidationError“注释”部分)。如果您需要根据其他字段验证某个字段,则必须首先检查它们是否已使用方法进行验证,如本答案(更新 2)所示。下面演示了一个示例,其中验证、和number 等字段(基于提供的)。提供的正则表达式模式只是用于本演示目的的示例,并且基于此和此答案。values.get()namecountry_codephonecountry_code
from pydantic import BaseModel, validator\nimport re\n\nname_pattern = re.compile(r\'[a-zA-Z\\s]+$\')\ncountry_codes = {"uk", "us"}\nUK_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\nUS_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\nphone_patterns = {"uk": UK_phone_pattern, "us": US_phone_pattern}\n\nclass Parent(BaseModel):\n name: str\n comments: str\n \nclass Customer(Parent):\n address: str\n country_code: str\n phone: str\n\n @validator(\'name\', \'country_code\', \'phone\')\n def validate_atts(cls, v, values, field):\n if field.name == "name":\n if not name_pattern.match(v): raise ValueError(f\'{v} is not a valid name.\')\n elif field.name == "country_code":\n if not v.lower() in country_codes: raise ValueError(f\'{v} is not a valid country code.\')\n elif field.name == "phone" and values.get(\'country_code\'):\n c_code = values.get(\'country_code\').lower()\n if not phone_patterns[c_code].match(v): raise ValueError(f\'{v} is not a valid phone number.\')\n return v\nRun Code Online (Sandbox Code Playgroud)\n在 Pydantic V2 中,@validator已被弃用,并被@field_validator. 如果您想values从 中的另一个字段进行访问@field_validator,可以使用ValidationInfo.data,它是字段名称到字段值的字典。
from pydantic import BaseModel, ValidationInfo, field_validator\nimport re\n\n# ... the rest of the code is the same as above\n\n\nclass Customer(Parent):\n address: str\n country_code: str\n phone: str\n\n @field_validator(\'name\', \'country_code\', \'phone\')\n @classmethod\n def validate_atts(cls, v: str, info: ValidationInfo):\n if info.field_name == \'name\':\n if not name_pattern.match(v): raise ValueError(f\'{v} is not a valid name.\')\n elif info.field_name == \'country_code\':\n if not v.lower() in country_codes: raise ValueError(f\'{v} is not a valid country code.\')\n elif info.field_name == \'phone\' and info.data.get(\'country_code\'):\n c_code = info.data.get(\'country_code\').lower()\n if not phone_patterns[c_code].match(v): raise ValueError(f\'{v} is not a valid phone number.\')\n return v\nRun Code Online (Sandbox Code Playgroud)\n@root_validator装饰器另一种方法是使用@root_validator,它允许对整个模型的数据执行验证。
from pydantic import BaseModel, root_validator\nimport re\n\nname_pattern = re.compile(r\'[a-zA-Z\\s]+$\')\ncountry_codes = {"uk", "us"}\nUK_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\nUS_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\nphone_patterns = {"uk": UK_phone_pattern, "us": US_phone_pattern}\n\nclass Parent(BaseModel):\n name: str\n comments: str\n \nclass Customer(Parent):\n address: str\n country_code: str\n phone: str\n\n @root_validator()\n def validate_atts(cls, values):\n name = values.get(\'name\')\n comments = values.get(\'comments\')\n address = values.get(\'address\')\n country_code = values.get(\'country_code\')\n phone = values.get(\'phone\')\n \n if name is not None and not name_pattern.match(name): \n raise ValueError(f\'{name} is not a valid name.\')\n if country_code is not None and not country_code.lower() in country_codes: \n raise ValueError(f\'{country_code} is not a valid country code.\')\n if phone is not None and country_code is not None:\n if not phone_patterns[country_code.lower()].match(phone): \n raise ValueError(f\'{phone} is not a valid phone number.\')\n \n return values\nRun Code Online (Sandbox Code Playgroud)\n在 Pydantic V2 中,@root_validator已被弃用,并被@model_validator. 模型验证器可以是mode=\'before\',mode=\'after\'或mode=\'wrap\'。在这种情况下,mode=\'after\'最适合。如文档中所述:
\n\n\n
mode=\'after\'验证器是实例方法,并且始终接收模型的\实例作为第一个参数。您不应将(cls, ModelType)其用作签名,而应仅使用并让类型\n检查器为您(self)推断 的类型。由于它们是完全类型安全的,因此它们通常比验证器self更容易实现。mode=\'before\'如果任何字段验证失败,mode=\'after\'则不会调用该字段的\n验证器。
mode=\'after\'from pydantic import BaseModel, model_validator\nimport re\n\n# ... the rest of the code is the same as above\n\n\nclass Customer(Parent):\n address: str\n country_code: str\n phone: str\n\n @model_validator(mode=\'after\')\n def validate_atts(self):\n name = self.name\n comments = self.comments\n address = self.address\n country_code = self.country_code\n phone = self.phone\n \n if name is not None and not name_pattern.match(name): \n raise ValueError(f\'{name} is not a valid name.\')\n if country_code is not None and not country_code.lower() in country_codes: \n raise ValueError(f\'{country_code} is not a valid country code.\')\n if phone is not None and country_code is not None:\n if not phone_patterns[country_code.lower()].match(phone): \n raise ValueError(f\'{phone} is not a valid phone number.\')\n \n return self\nRun Code Online (Sandbox Code Playgroud)\nmode=\'before\'如果您更愿意使用mode=\'before,您可以按如下方式操作。但请注意,在这种情况下,您应该在继续进一步str处理/验证(例如,将值转换为小写、字符串值比较等)\xe2\x80\x94 不包含在下面。
from pydantic import BaseModel, model_validator\nfrom typing import Any\nimport re\n\n# ... the rest of the code is the same as above\n\n\nclass Customer(Parent):\n address: str\n country_code: str\n phone: str\n\n @model_validator(mode=\'before\')\n @classmethod\n def validate_atts(cls, data: Any):\n if isinstance(data, dict):\n name = data.get(\'name\')\n comments = data.get(\'comments\')\n address = data.get(\'address\')\n country_code = data.get(\'country_code\')\n phone = data.get(\'phone\')\n \n if name is not None and not name_pattern.match(name): \n raise ValueError(f\'{name} is not a valid name.\')\n if country_code is not None and not country_code.lower() in country_codes: \n raise ValueError(f\'{country_code} is not a valid country code.\')\n if phone is not None and country_code is not None:\n if not phone_patterns[country_code.lower()].match(phone): \n raise ValueError(f\'{phone} is not a valid phone number.\')\n \n return data\nRun Code Online (Sandbox Code Playgroud)\nfrom pydantic import ValidationError\n\n# should throw "Value error, (123) 123-1234 is not a valid phone number."\ntry:\n Customer(name=\'john\', comments=\'hi\', address=\'some address\', country_code=\'UK\', phone=\'(123) 123-1234\')\nexcept ValidationError as e:\n print(e)\n\n# should work without errors\nprint(Customer(name=\'john\', comments=\'hi\', address=\'some address\', country_code=\'UK\', phone=\'+44 7222 555 555\'))\nRun Code Online (Sandbox Code Playgroud)\n
首先,如果您在导入root_validator时遇到错误,我会更新 pydantic。
pip install -U pydantic
Run Code Online (Sandbox Code Playgroud)
上面的许多示例向您展示了如何一次对多个值使用相同的验证器。或者它们会增加很多不必要的复杂性来完成你想要的事情。您可以简单地使用以下代码使用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'}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5768 次 |
| 最近记录: |