Pydantic - how to skip validation of other fields if one of the fields fails?

Let's say I have a simple pydantic.BaseModel like this:

from myapp import User
from pydantic import BaseModel, validator
class ChangePasswordRequest(BaseModel): class Config: arbitrary_types_allowed = True # because I'm using my `User` arbitrary type user: User current_password: constr(min_length=1, max_length=255) new_password: constr(min_length=8, max_length=64) @validator("user") def user_is_active(cls, user: User): assert not user.inactive, "User is not active." return user @validator("current_password") def current_password_validator(cls, password: str, values: Dict[str, Any]): user: User = values["user"] assert user.check_password(password), "current_password is not valid." return password

This is the model I'd like to use to handle user's password change. When I create ChangePasswordRequest with inactive user, I get a KeyError, because pydatinc validates all the fields.

from myapp import User
user = User(inactive=True)
r = ChangePasswordRequest(user=user, current_password="current", new_password="new-password")
# I get
KeyError: 'user'

The reason why it happens:

  • user_is_active is called and validation fails. values["user"] is not set as an effect
  • current_password_validator is called. values["user"] key does not exist and KeyError is raised.

What I want to achieve is to skip all validation if user field validation fails as there is no point of further validation. This is not a problem for a small model like mine as I can add an if statement in each validator, but this gets annoying as model grows.

@validator("current_password")
def current_password_validator(cls, password: str, values: Dict[str, Any]): if not user := values.get("user"): return password assert user.check_password(password), "current_password is not valid." return password

Other way would be to use root_validator(pre=True), but there is another problem with this approach. Error is located in the __root__ field, instead of user field.

@root_validator(pre=True)
def user_is_active(cls, values: Dict[str, Any]): user: Union[User, None] = values.get("user", None) assert getattr(user, "is_active", False), "User is not active." return values
# which produces following error:
[{'loc': ['__root__'], 'msg': 'User is not active.', 'type': 'assertion_error'}]

Does pydantic have any feature that will stop further validation if one of the "main" or "crucial" fields fails?

5

1 Answer

Instead of trying to stop execution after the first validator, you can begin the second one with something like this:

if "user" not in values: raise ValueError("Could not validate current_password because user did not pass validation")

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like