7

我想验证 pydantic 模型的三个模型字段。为此,我从 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):

我从一些常见的字段父模型继承了我的 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.
4

4 回答 4

14

为了扩展 的答案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")

输出

<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("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)(参数名称valuesfield并且config 必须匹配)可以通过以下方式访问字段的值字段名称作为键(例如values["comments"])。

编辑:如果您只想检查某种类型的输入值,您可以使用以下结构:

@validator("*") # validates all fields
def validate_if_float(cls, value):
    if isinstance(value, float):
        # do validation here
    return value
于 2021-07-22T13:59:44.940 回答
5

您需要将字段作为装饰器的参数传递。

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):
于 2020-06-24T04:24:25.007 回答
0

根据文档,“一个validator可以通过传递多个字段名称来应用于多个字段”(并且“也可以通过传递特殊值在所有'*'字段上调用”)。因此,您可以将希望验证的字段添加到validator装饰器,并使用field.name属性检查每次validator调用时要验证的字段。如果一个字段没有通过验证,您可以raise ValueError“将被捕获并用于填充”(请参阅​​此处ValidationError的“注意”部分)。如果您需要根据其他字段验证字段,则必须首先检查它们是否已经使用方法进行了验证,如本答案所示(更新 2)values.get(). 下面演示了一个示例,其中验证了 、 和 number 等字段namecountry_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
于 2022-02-24T20:54:01.063 回答
-1

此示例包含回答您的问题所需的所有信息。

    class User(BaseModel):
        name: Optional[str] = ""

        class Config:
            validate_assignment = True

        @validator("name")
            def set_name(cls, name):
            return name or "foo"
于 2021-11-16T11:29:58.990 回答