繁体   English   中英

如何验证 pydantic model 的多个字段

[英]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装饰器中。
  • 验证 function ( 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) (参数名称valuesfieldconfig必须匹配)可以使用字段名称作为键访问字段的值(例如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) 下面演示了一个示例,其中验证了namecountry_codephone号码等字段(基于提供的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM