簡體   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