Pydantic: How to have a single validator for multiple fields?

Created on 14 May 2019  路  8Comments  路  Source: samuelcolvin/pydantic

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(...)
question

Most helpful comment

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.

All 8 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iwoloschin picture iwoloschin  路  3Comments

vvoody picture vvoody  路  3Comments

samuelcolvin picture samuelcolvin  路  3Comments

engstrom picture engstrom  路  3Comments

bartekbrak picture bartekbrak  路  3Comments