fromtypingimportAnnotatedfrompydanticimportAfterValidator,BaseModel,ValidationErrordefis_even(value:int)->int:ifvalue%2==1:raiseValueError(f'{value} is not an even number')returnvalue# (1)!classModel(BaseModel):number:Annotated[int,AfterValidator(is_even)]try:Model(number=1)exceptValidationErroraserr:print(err) 1 validation error for Model number Value error, 1 is not an even number [type=value_error, input_value=1, input_type=int]
frompydanticimportBaseModel,ValidationError,field_validatorclassModel(BaseModel):number:int@field_validator('number',mode='after')# (1)!@classmethoddefis_even(cls,value:int)->int:ifvalue%2==1:raiseValueError(f'{value} is not an even number')returnvalue# (2)!try:Model(number=1)exceptValidationErroraserr:print(err) 1 validation error for Model number Value error, 1 is not an even number [type=value_error, input_value=1, input_type=int]
fromtypingimportAnnotated,AnyfrompydanticimportBaseModel,BeforeValidator,ValidationErrordefensure_list(value:Any)->Any:# (1)!ifnotisinstance(value,list):# (2)!return[value]else:returnvalueclassModel(BaseModel):numbers:Annotated[list[int],BeforeValidator(ensure_list)]print(Model(numbers=2))#> numbers=[2]try:Model(numbers='str')exceptValidationErroraserr:print(err)# (3)! 1 validation error for Model numbers.0 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='str', input_type=str]
Pydantic 仍然对 int 类型执行验证,无论我们的 ensure_list 验证器是否对原始输入类型进行了操作。
fromtypingimportAnyfrompydanticimportBaseModel,ValidationError,field_validatorclassModel(BaseModel):numbers:list[int]@field_validator('numbers',mode='before')@classmethoddefensure_list(cls,value:Any)->Any:# (1)!ifnotisinstance(value,list):# (2)!return[value]else:returnvalueprint(Model(numbers=2))#> numbers=[2]try:Model(numbers='str')exceptValidationErroraserr:print(err)# (3)! 1 validation error for Model numbers.0 Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='str', input_type=str]
fromtypingimportAnyfromtypingimportAnnotatedfrompydanticimportBaseModel,Field,ValidationError,ValidatorFunctionWrapHandler,field_validatorclassModel(BaseModel):my_string:Annotated[str,Field(max_length=5)]@field_validator('my_string',mode='wrap')@classmethoddeftruncate(cls,value:Any,handler:ValidatorFunctionWrapHandler)->str:try:returnhandler(value)exceptValidationErroraserr:iferr.errors()[0]['type']=='string_too_long':returnhandler(value[:5])else:raiseprint(Model(my_string='abcde'))#> my_string='abcde'print(Model(my_string='abcdef'))#> my_string='abcde'defis_even(value:int)->int:ifvalue%2==1:raiseValueError(f'{value} is not an even number')returnvalueEvenNumber=Annotated[int,AfterValidator(is_even)]classModel1(BaseModel):my_number:EvenNumberclassModel2(BaseModel):other_number:Annotated[EvenNumber,AfterValidator(lambdav:v+2)]classModel3(BaseModel):list_of_even_numbers:list[EvenNumber]# (1)!
fromtyping_extensionsimportSelffrompydanticimportBaseModel,model_validatorclassUserModel(BaseModel):username:strpassword:strpassword_repeat:str@model_validator(mode='after')defcheck_passwords_match(self)->Self:ifself.password!=self.password_repeat:raiseValueError('Passwords do not match')returnself
fromtypingimportAnyfrompydanticimportBaseModel,model_validatorclassUserModel(BaseModel):username
:str@model_validator(mode='before')@classmethoddefcheck_card_number_not_present(cls,data:Any)->Any:# (1)!ifisinstance(data,dict):# (2)!if'card_number'indata:raiseValueError("'card_number' should not be included")returndata
importloggingfromtypingimportAnyfromtyping_extensionsimportSelffrompydanticimportBaseModel,ModelWrapValidatorHandler,ValidationError,model_validatorclassUserModel(BaseModel):username:str@model_validator(mode='wrap')@classmethoddeflog_failed_validation(cls,data:Any,handler:ModelWrapValidatorHandler[Self])->Self:try:returnhandler(data)exceptValidationError:logging.error('Model %s failed to validate with data %s',cls,data)raise
frompydantic_coreimportPydanticCustomErrorfrompydanticimportBaseModel,ValidationError,field_validatorclassModel(BaseModel):x:int@field_validator('x',mode='after')@classmethoddefvalidate_x(cls,v:int)->int:ifv%42==0:raisePydanticCustomError('the_answer_error','{number} is the answer!',{'number':v},returnvtry:Model(x=42*2)exceptValidationErrorase:print(e) 1 validation error for Model 84 is the answer! [type=the_answer_error, input_value=84, input_type=int]
frompydanticimportBaseModel,ValidationInfo,field_validatorclassUserModel(BaseModel):password:strpassword_repeat:strusername:str@field_validator('password_repeat',mode='after')@classmethoddefcheck_passwords_match(cls,value:str,info:ValidationInfo)->str:ifvalue!=info.data['password']:raiseValueError('Passwords do not match')returnvalue
frompydanticimportBaseModel,ValidationInfo,field_validatorclassModel(BaseModel):text:str@field_validator('text',mode='after')@classmethoddefremove_stopwords(cls,v:str,info:ValidationInfo)->str:ifisinstance(info.context,dict):stopwords=info.context.get('stopwords',set())v=' '.join(wforwinv.split()ifw.lower()notinstopwords)returnvdata={'text':'This is an example document'}print(Model.model_validate(data))# no context#> text='This is an example document'print(Model.model_validate(data,context={'stopwords':['this','is','an']}))#> text='example document'
frompydanticimportBaseModel,InstanceOf,ValidationErrorclassFruit:def__repr__(self):returnself.__class__.__name__classBanana(Fruit):...classApple(Fruit):...classBasket(BaseModel):fruits:list[InstanceOf[Fruit]]print(Basket(fruits=[Banana(),Apple()]))#> fruits=[Banana, Apple]try:Basket(fruits=[Banana(),'Apple'])exceptValidationErrorase:print(e) 1 validation error for Basket fruits.1 Input should be an instance of Fruit [type=is_instance_of, input_value='Apple', input_type=str]