【问题标题】:Pydantic: validating a nested modelPydantic:验证嵌套模型
【发布时间】:2021-09-06 00:20:21
【问题描述】:

我在 Pydantic 中有一个嵌套模型。我在外部模型中有一个root_validator 函数。我的印象是,如果调用外部根验证器,则内部模型是有效的。但显然不是。在下面的 MWE 中,我给内部模型提供了错误的字段名称,但外部验证器失败了:

from typing import List
from pydantic import BaseModel
from pydantic.class_validators import root_validator

class CarList(BaseModel):
    cars: List[str]
    colors: List[str]

class CarDealership(BaseModel):
    name: str
    cars: CarList

    @root_validator()
    def check_length(cls, v):
        cars_list = v.get("cars")

        if len(cars_list.cars) != len(cars_list.colors):
            raise ValueError("wrong length")
        
        return v


car_deal = {
    "cars": {
        "cars1": ["toyota", "tesla"], 
        "colors": ["white", "red"]
    }
}

CarDealership.parse_obj(car_deal)

我得到的错误是:

  File "test.py", line 17, in check_length
    if len(cars_list.cars) != len(cars_list.colors):
AttributeError: 'NoneType' object has no attribute 'cars'

我期待的是这样的:

pydantic.error_wrappers.ValidationError: 1 validation error for CarList
cars
  field required (type=value_error.missing)

如何确保首先验证内部模型?

【问题讨论】:

    标签: python pydantic


    【解决方案1】:

    更新:外部类版本的验证

    from typing import List
    from pydantic import BaseModel
    from pydantic.class_validators import root_validator
    
    
    class CarList(BaseModel):
        cars: List[str]
        colors: List[str]
    
    
    class CarDealership(BaseModel):
        name: str
        cars_list: CarList
    
        @root_validator(pre=True)
        def check_length(cls, v):
            cars_list = v.get("cars_list")
    
            if not cars_list:
                return v
            cars = cars_list.get("cars")
            colors = cars_list.get("colors")
            if not isinstance(cars, list) or not isinstance(colors, list):
                return v
            if cars is not None and colors is not None and len(cars) != len(colors):
                raise ValueError("wrong length")
    
            return v
    

    root_validator默认pre=False,内部模型已经验证,所以你得到v == {}

    您可以在CarList中创建check_length,并检查carscolors是否存在(已经验证,如果失败则为None)。

    from typing import List
    from pydantic import BaseModel
    from pydantic.class_validators import root_validator
    
    
    class CarList(BaseModel):
        cars: List[str]
        colors: List[str]
    
        @root_validator
        def check_length(cls, v):
            cars = v.get("cars")
            colors = v.get("colors")
    
            if cars is not None and colors is not None and len(cars) != len(colors):
                raise ValueError("wrong length")
    
            return v
    
    
    class CarDealership(BaseModel):
        name: str
        car_list: CarList
    
    
    car_deal_1 = {
        "name": "value",
        "car_list": {
            "cars1": ["toyota", "tesla"],
            "colors": ["white", "red"]
        }
    }
    
    CarDealership.parse_obj(car_deal_1)
    # pydantic.error_wrappers.ValidationError: 1 validation error for CarDealership
    # car_list -> cars
    #   field required (type=value_error.missing)
    
    car_deal_2 = {
        "name": "value",
        "car_list": {
            "cars": ["toyota", "tesla"],
            "colors": ["white", "red", "bule"]
        }
    }
    
    CarDealership.parse_obj(car_deal_2)
    # pydantic.error_wrappers.ValidationError: 1 validation error for CarDealership
    # car_list -> __root__
    #   wrong length (type=value_error)
    

    【讨论】:

    • 问题是我想在外部类上进行验证,因为我想将内部类用于不需要此验证的其他目的。
    【解决方案2】:

    基于@YeJun 响应,但假设您对响应的评论是您需要将内部类用于其他目的,您可以创建一个带有验证的中间类,同时保留原始 CarList 类用于其他用途:

    from typing import List
    from pydantic import BaseModel
    from pydantic.class_validators import root_validator
    
    
    class CarList(BaseModel):
        cars: List[str]
        colors: List[str]
    
    
    # this class will have the same fields from CarList, but with validation
    class CarListWithValidator(CarList):
        @root_validator
        def check_length(cls, v):
            cars = v.get("cars")
            colors = v.get("colors")
    
            if cars is not None and colors is not None and len(cars) != len(colors):
                raise ValueError("wrong length")
    
            return v
    
    
    class CarDealership(BaseModel):
        name: str
        car_list: CarListWithValidator
    
    
    car_deal_2 = {
        "name": "value",
        "car_list": {
            "cars": ["toyota", "tesla"],
            "colors": ["white", "red", "bule"]
        }
    }
    
    CarDealership.parse_obj(car_deal_2)
    # pydantic.error_wrappers.ValidationError: 1 validation error for CarDealership
    # car_list -> __root__
    #   wrong length (type=value_error)
    

    【讨论】:

      猜你喜欢
      • 2022-01-15
      • 2022-07-28
      • 2012-12-12
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 1970-01-01
      • 2022-11-26
      • 2012-08-28
      相关资源
      最近更新 更多