Skip to content
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

✨ Add a config field to make all model fields optional #3121

Closed
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/3121-christophelec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a `total` configuration field to create models with all fields Optional
christophelec marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 4 additions & 0 deletions docs/usage/model_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ not be included in the model schemas. **Note**: this means that attributes on th
**`copy_on_model_validation`**
: whether or not inherited models used as fields should be reconstructed (copied) on validation instead of being kept untouched (default: `True`)

**`total`**
: whether all fields must be present in the model. Setting this to `False` is equivalent to manually setting all fields as `Optional` with a `None` default (default: `True`)


## Change behaviour globally

If you wish to change the behaviour of _pydantic_ globally, you can create your own custom `BaseModel`
Expand Down
5 changes: 4 additions & 1 deletion pydantic/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class BaseConfig:
json_dumps: Callable[..., str] = json.dumps
json_encoders: Dict[Type[Any], AnyCallable] = {}
underscore_attrs_are_private: bool = False
total: bool = True

# Whether or not inherited models as fields should be reconstructed as base model
copy_on_model_validation: bool = True
Expand Down Expand Up @@ -96,7 +97,9 @@ def prepare_field(cls, field: 'ModelField') -> None:
"""
Optional hook to check or modify fields during model creation.
"""
pass
if not cls.total:
field.type_ = Optional[field.type_]
field.required = False
Comment on lines +100 to +102
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if not cls.total:
field.type_ = Optional[field.type_]
field.required = False
if not cls.total:
field.required = False

@lsapan is right. We shouldn't change the type and accept None.
Making it non required is enough



def inherit_config(self_config: 'ConfigType', parent_config: 'ConfigType', **namespace: Any) -> 'ConfigType':
Expand Down
20 changes: 20 additions & 0 deletions tests/test_create_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,23 @@ class Config:

m2 = create_model('M2', __config__=Config, a=(str, Field(...)))
assert m2.schema()['properties'] == {'a': {'title': 'A', 'description': 'descr', 'type': 'string'}}


def test_config_all_optional_fields_model():
class Config:
total = False

m1 = create_model('M1', __config__=Config, a=(str, ...))
assert m1()


def test_config_all_optional_fields_model_inheritance():
class TestBase(BaseModel):
b: str

class Test(TestBase, total=False):
a: str

with pytest.raises(ValidationError):
TestBase()
assert Test()