You mean like this?
from typing import Any
from pydantic import BaseModel, ValidationError, root_validator
class RequestModel(BaseModel):
types: list[str]
segments: list[str] = []
@root_validator
def my_validator(cls, values: dict[str, Any]) -> dict[str, Any]:
if len(values.get("types", [])) > 1 and values["segments"]:
raise ValueError("Your error message here")
return values
if __name__ == "__main__":
print(RequestModel(types=["foo"], segments=["a"]))
print(RequestModel(types=["bar"]))
print(RequestModel(types=[], segments=["b", "c"]))
try:
RequestModel(types=["spam", "eggs"], segments=["x"])
except ValidationError as e:
print(e)
Output:
types=['foo'] segments=['a']
types=['bar'] segments=[]
types=[] segments=['b', 'c']
1 validation error for RequestModel
__root__
Your error message here (type=value_error)
An alternative is to use a normal @validator
on the segments
field and utilize the optional values
parameter there. (see docs)
This is how that could look:
from typing import Any
from pydantic import BaseModel, ValidationError, validator
class RequestModel(BaseModel):
types: list[str]
segments: list[str] = []
@validator("segments")
def my_validator(cls, v: list[str], values: dict[str, Any]) -> list[str]:
if len(values.get("types", [])) > 1 and v:
raise ValueError("Your error message here")
return v
if __name__ == "__main__":
print(RequestModel(types=["foo"], segments=["a"]))
print(RequestModel(types=["bar"]))
print(RequestModel(types=[], segments=["b", "c"]))
try:
RequestModel(types=["spam", "eggs"], segments=["x"])
except ValidationError as e:
print(e)
Output is equivalent with a slightly different error structure.
Here the order of the fields matters because values
will only contain those that were already validated and validation is done in the order that fields are defined. So you can not do this with a @validator("types")
because by the time that validator is called, values
will not contain an entry for segments
yet.
PS: The reason I used len(values.get("types", []))
instead of len(values["types"])
in both cases is to ensure a properly formed error message. types
is a required field and a validation error will therefore occur anyway, if the user tries to initialize an instance without providing a value for it. But Pydantic models will still go through the entire validation cycle anyway, and collect all occurrences of ValueError
, TypeError
, and AssertionError
, before giving out a comprehensive error message about all of them.
If we simply tried to get values["types"]
, but that key was not present in the dictionary because the user failed to provide it, this would trigger a KeyError
, which is not properly processed as a ValidationError
by Pydantic.