This seems pretty basic so I wouldn't be surprised if I'm missing something obvious, but from a close read of the documentation I can't figure out how to have a validator which acts on multiple fields in a BaseModel, i.e. something like
class Model(BaseModel):
foo: int
bar: int
@model_validator(...)
def compare_foo_and_bar(cls):
# This is a nonsense example
if not (foo - bar):
raise ValueError(...)
Away from my computer so can't give a full example, but basically, the validator can take values as an argument.
The docs has an example with passwords.
Cool, thanks. For posterity here's the example mentioned (I think): https://github.com/jamesob/pydantic/blob/fe72ba13f469377057112d2f301f52cd3b206467/docs/examples/validators_simple.py#L14-L20
This looks like values is the raw data coming in - is there a way to do a post-deserialization validation on the resulting BaseModel instance?
Not on the resulting Model (unless you did it manually yourself), but I don't think values is "raw data", I think it's already been validated.
Cool, thanks for the great library.
BUT that means when foo changes, then the value param is whatever foo is, and whenever bar changes, value becomes whatever bar is
No it doesn't. This is just a validator, it's a function that is called when these values are validated, it doesn't mean foo is set to bar or visa-versa.
not telling you which one
No it doesn't. You can use use the field argument to identify which field is changing.
More generally: if you want help you would be well advised to change your tone.
If you are going state negative/critical things, take some time to check that what you're saying is correct. Incorrect, negative assertions are a pretty efficient way of pissing people off.
@samuelcolvin
I don't understand, sorry, so if, for instance, I want to verify if either of fields: foo or boo exists but not both at the same time, how can I do that?
Thanks.
Hi @anikolaienko
You could go with something like this
from typing import Dict, Optional
from pydantic import BaseModel, validator
class Model(BaseModel):
foo: Optional[str]
boo: Optional[str]
# Validate the second field 'boo' to have 'foo' in `values` variable
# We set `always=True` to run the validator even if 'boo' field is not set
@validator('boo', always=True)
def ensure_only_foo_or_boo(cls, boo: Optional[str], values: Dict[str, Optional[str]]):
foo = values.get('foo')
if foo is not None and boo is not None:
raise ValueError('only one of "foo" or "boo" can be set')
if foo is None and boo is None:
raise ValueError('one of "foo" or "boo" needs to be set')
return boo
Hope it helps!
Hi @PrettyWood , I appreciate your help! But this doesn't work for me. I still don't understand what is values because in my case values is empty dictionary when boo is not present.
I figured that I can use root_validator(cls, values): very nice and easy for this purpose.
Most helpful comment
No it doesn't. This is just a validator, it's a function that is called when these values are validated, it doesn't mean
foois set tobaror visa-versa.No it doesn't. You can use use the
fieldargument to identify which field is changing.More generally: if you want help you would be well advised to change your tone.
If you are going state negative/critical things, take some time to check that what you're saying is correct. Incorrect, negative assertions are a pretty efficient way of pissing people off.