New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Question] At least one field required #506
Comments
No problem, pleased it's helpful. Simplest solution is to use a something like class MyModel(BaseModel):
a: str = None
b: str = None
@validator('b')
def check_a_or_b(cls, v, values):
if 'a' not in values and not b:
raise ValueError('either a or b is required')
return b Unfortunately:
pydantic currently has no concept of errors that don't apply to field, so if you wanted something else you'd have to implement it manually at the moment. Let me know if that works for you. |
ah ok, unfortunately I need to be able to generate the correct JSONSchema from it, so I guess this is currently not supported. but thanks for the quick response, anyways! |
Happy to try and accept it, but this would probably be a big change for pydantic since it lives "above" the fields where most validation currently goes on. I'm not even sure how you would define it for the schema. |
Hi there! I'm facing a similar issue here, where I'm trying to ensure that either a or b is being passed in. I'm using a It's unclear if the params are required - Also, considering that the purpose of using type hints to convey notation, this actually triggers a mypy warning:
I tried wrapping the value with |
@miketheman can you share the code that is resulting in mypy errors? @timonbimon As of pydantic 0.32, it is now possible to manually specify updates to the generated json schema via the This should make it possible for you to generate your intended JSON schema. |
@dmontagu certainly! I basically took the code from the example earlier in this thread - #506 (comment) from pydantic import validator
from pydantic.dataclasses import dataclass
@dataclass
class MyModel:
a: str = None
b: str = None
@validator('b')
def check_a_or_b(cls, v, values):
if 'a' not in values and not b:
raise ValueError('either a or b is required')
return b And $ mypy sample.py
sample.py:7: error: Incompatible types in assignment (expression has type "None", variable has type "str")
sample.py:8: error: Incompatible types in assignment (expression has type "None", variable has type "str") |
@miketheman annotate the str as Optional[str] (using |
@dmontagu Certainly! Adding the Optional type removes the mypy errors, but then the validator doesn't get applied. Here's a couple of examples: from typing import Optional
from pydantic import validator
from pydantic.dataclasses import dataclass
@dataclass
class MyModel:
a: Optional[str] = None
b: Optional[str] = None
@validator('b')
def check_a_or_b(cls, v, values):
if 'a' not in values and not b:
raise ValueError('either a or b is required')
return b
mm = MyModel(a="a")
print(mm) Output:
So it appears that the validator isn't being called yet. If I add ...
@validator('b', always=True)
def check_a_or_b(cls, v, values):
... Output:
Using Any ideas? |
def check_a_or_b(cls, v, values):
if 'a' not in values and not b:
raise ValueError('either a or b is required')
return b
|
@dmontagu Thanks for pointing that out - that led me further along - I completely overlooked that, the original example had the error already, I simply copied it without actually understanding what it was doing. I changed Once corrected, it still doesn't do the behavior needed, due to the @validator('b')
def check_a_or_b(cls, b, values):
if not values.get('a') and not b:
raise ValueError('either a or b is required')
return b So now the validator logic seems correct, as the My understanding from the docs is that if a value is not supplied, the validator won't run, so the Adding that to the
The docs call out that adding
So changing it to add Sample code, updated, for reference, and ought to be runnable: from typing import Optional
from pydantic import validator
from pydantic.dataclasses import dataclass
@dataclass
class MyModel:
a: Optional[str] = None
b: Optional[str] = None
@validator('b', pre=True, always=True)
def check_a_or_b(cls, b, values):
if not values.get('a') and not b:
raise ValueError('either a or b is required')
return b
mm = MyModel() Error output:
This last bit is more in line with what I've been looking for - thanks for taking the time to read through my learning process and guiding! - but the duplicate validation error feels incorrect, so I'm wondering if there's some other elegant way to solve this. |
Yes, this get's me occasionally too. The reason for the duplicate error is that The solution here is to use from typing import Optional
from pydantic import validator
from pydantic.dataclasses import dataclass
@dataclass
class MyModel:
a: Optional[str] = None
b: Optional[str] = None
@validator('b', pre=True, always=True, whole=True)
def check_a_or_b(cls, b, values):
if not values.get('a') and not b:
raise ValueError('either a or b is required')
return b
mm = MyModel() Because we have This is ugly and I don't like it, but I'm not sure how to fix it. Possible solutions:
|
@samuelcolvin I think my favorite of those options is deduplicating in the |
okay, I might try the third option, or some better solution than |
I think this is fixed on master, create a new issue or comment here if you think I'm wrong. |
Confirming that on pydantic 1.0b2 I can remove any of the validator keyword parameters to get the desired result. From the last example: - @validator('b', pre=True, always=True, whole=True)
+ @validator('b') And the output: $ python repro.py
Traceback (most recent call last):
File "repro.py", line 16, in <module>
mm = MyModel()
File "<string>", line 4, in __init__
File "pyenv/lib/python3.7/site-packages/pydantic/dataclasses.py", line 77, in _pydantic_post_init
raise validation_error
pydantic.error_wrappers.ValidationError: 1 validation error for MyModel
b
either a or b is required (type=value_error) Thanks @samuelcolvin & others! I couldn't figure out which commit exactly solved this, but happy with the path to 1.0 release. |
This can also be done using the
Not sure which is preferred though. |
root_validator will do the job have a look https://docs.pydantic.dev/usage/validators/#root-validators |
Pydantic 2.x note:
|
Is there a way to trigger the 'missing' error to align with Pydantic's 'Field missing' message and structure? |
Another way to do it is with If you really need a "good jsonschema", it is better than model validation. import json
from pydantic import BaseModel, RootModel
class MyModelBOptional(BaseModel):
a: int
b: int | None = 42
class MyModelAOptional(BaseModel):
a: int | None = 42
b: int
class MyModelRoot(RootModel):
root: MyModelAOptional | MyModelBOptional
print(json.dumps(MyModelRoot.model_json_schema(), indent=2))
print(MyModelRoot({"a": 10}))
print(MyModelRoot({"b": 10}))
|
Question
Hi there, thanks for a super cool library! Pydantic has slowly been replacing all other data validation libraries in my projects. :)
As to my question:
I want to validate a JSON that can have one or two keys (each gets a default value if it is not present) but at least one is required.
Let's call the two keys "a" and "b" => in that case I would like these JSONs to be valid
and these to be invalid
With Jsonschema I can do this, like so:
Any ideas how to do this with Pydantic?
Any help is greatly appreciated :)
The text was updated successfully, but these errors were encountered: