Search code examples
python-3.xvalidationpydanticpython-dataclasses

How to get the type of a validated field in Pydantic validator method


I want to assign a value of None to a field that fails to validate in Pydantic. The validator has a list of fields that it tries to validate.

To validate each field using data, fields_set, e = validate_model(model, raw_data) I need to know the model of each field.

I would like to have something like this for a validator.

Is there a way to discover the type of the field that is being validated???

    @validator('*', pre=True)
    def validate_name(cls, value: str):
        model_of_field = ..... Some method to discover the field's Type(s)
        data, fields_set, e = validate_model(model_of_field, value)
        return value

Example that declares a separate validator method for each field

Note that the field is named "name1" on purpose to fail the validation and make it return None.

from typing import Any, Optional

from pydantic import BaseModel, validator, validate_model, ValidationError


class NameModel(BaseModel):
    name: str


class AgeModel(BaseModel):
    age: int


class MyModel(BaseModel):
    name_data: Optional[NameModel]
    age_data: Optional[AgeModel]

    @classmethod
    def pre_validate_any_field_and_return_none_on_validation_error(cls, model: Any,  value: Any):
        data, fields_set, e = validate_model(model, value)
        if e:
            return None
        else:
            return value


    @validator('name_data', pre=True)
    def validate_name(cls, value: str):
        return cls.pre_validate_any_field_and_return_none_on_validation_error(NameModel, value)


    @validator('age_data', pre=True)
    def validate_age(cls, value: int):
        return cls.pre_validate_any_field_and_return_none_on_validation_error(AgeModel, value)


my_data = {
    'name_data': {'name1': 'Hello_a'},
    'age_data': {'age': 120}
}

my_object: MyModel = MyModel(**my_data)
print(my_object)

Solution

  • You should use the __fields__ property as documented here: https://pydantic-docs.helpmanual.io/usage/models/#model-properties. It will give you something like this:

    class Model(BaseModel):
        value: int
    
        @field_validator("value", mode='before')
        def validate_value(cls, v):
            print(cls.__fields__)
            # Do your logic here
            return v
    
    Model(1)
    

    This would print:

    {'value': ModelField(name='value', type=int, required=True)}