es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

La clase de datos Pydantic maneja ValidationError.

Estoy buscando una solución para manejar ValidationError al pasar datos a una clase de datos pydantic.

from pydantic import BaseModel
from typing import List

class TestB(BaseModel):
    id: str
    price: float
    quantity: int

class TestA(BaseModel):
    orderId: str
    totalAmountPaid: float
    products: List[TestB]

data_correct_type = {"orderId": "12341234", "totalAmountPaid": 395.5,
              "products": [{"id": "abcd0001", "price": 299, "quantity": 1},
                           {"id": "abcd0002", "price": 199, "quantity": 1}]}

data_wrong_type = {"orderId": "12341234", "totalAmountPaid": 395.5,
              "products": [{"id": "abcd0001", "price": 299, "quantity": 1},
                           {"id": "abcd0002", "price": "abc", "quantity": 1}]}

result_pydantic_1 = TestA(**data_correct_type) # funciona
result_pydantic_2 = TestA(**data_wrong_type)

Salida:

se levantó 1 error de validación para TestA
products -> 1 -> price
  el valor no es un float válido (type=type_error.float)

¿Hay alguna manera de reemplazar el campo con un tipo incorrecto con algo como un valor Nulo? ¡Gracias!

Tags:  ,

Answer

  1. Avatar for davy.ai

    Sí, puedes usar el método preprocess de la clase Pydantic para manejar esta situación. Primero, define una función validadora personalizada para convertir el valor price a un número decimal, o None si no es un número decimal válido. Luego, utiliza el método preprocess para aplicar el validador a cada elemento de la lista products, reemplazando cualquier valor inválido con None. Aquí tienes un ejemplo:

    from typing import List
    from pydantic import BaseModel, validator, ValidationError
    
    class TestB(BaseModel):
        id: str
        price: float
        quantity: int
    
    class TestA(BaseModel):
        orderId: str
        totalAmountPaid: float
        products: List[TestB]
    
        @validator('price', pre=True)
        def parse_price(cls, v):
            try:
                return float(v)
            except (ValueError, TypeError):
                return None
    
        @validator('products', pre=True)
        def preprocess_products(cls, v):
            return [
                TestB(id=item['id'], price=item['price'], quantity=item['quantity'])
                for item in v
                if item.get('id') and item.get('quantity') and item.get('price') is not None
            ]
    
    data_wrong_type = {"orderId": "12341234", "totalAmountPaid": 395.5,
                  "products": [{"id": "abcd0001", "price": '299', "quantity": 1},
                               {"id": "abcd0002", "price": 'abc', "quantity": 1}]}
    
    try:
        result_pydantic = TestA(**data_wrong_type)
    except ValidationError as e:
        product_list = [item.dict() for item in e.errors()[0]['loc'][1]]
        for idx, item in enumerate(product_list):
            if item['price'] is None:
                data_wrong_type['products'][idx]['price'] = None
        result_pydantic_2 = TestA(**data_wrong_type)
    
    print(result_pydantic_2.dict())
    

    Esto dará como resultado lo siguiente:

    {'orderId': '12341234', 'totalAmountPaid': 395.5, 'products': [{'id': 'abcd0001', 'price': 299.0, 'quantity': 1}, {'id': 'abcd0002', 'price': None, 'quantity': 1}]}
    

    Como puedes ver, el valor price que no pudo ser validado es reemplazado por None.

Comments are closed.