-
First and foremost, thank you for creating an amazingly useful package!! I occasionally have pydantic models in which all fields either:
In these instances, I want to create a model instance with all default field values prior to outputting its values (not schema) to JSON. However, as far as I can tell, there's no easy way to default initialize. Calling construct({}) partially fulfills this need, but does not recursively initialize submodels with default values. Below I've hacked together a function called default_initialize which could potentially be a class method in BaseModel (although it currently is not). Is there a better way of creating a BaseModel instance populated with all default values? from typing import Any, Dict, Type, TypeVar
from pydantic import BaseModel
_ModelType = TypeVar("_ModelType", bound=BaseModel)
def default_initialize(model: Type[_ModelType]) -> _ModelType:
"""Return an instance of the model recursively populated with default values.
Requires that the model's fields all either:
- Have a default value
- Are models that are themselves default initializable
Raises:
ValueError: If any fields in the model or its sub-models have no default specified
"""
def _helper(submodel: Type[BaseModel]) -> Dict[str, Any]:
init_value_dict = {}
for key, field in submodel.__fields__.items():
if field.required:
if issubclass(field.type_, BaseModel):
init_value_dict[key] = _helper(field.outer_type_)
else:
if submodel == model:
raise ValueError(
f"Cannot default initialize model {model.__name__}, " f"as field '{field.name}' is required"
)
else:
raise ValueError(
f"Cannot default initialize model {model.__name__}, "
f"as field '{field.name}' in submodel '{submodel.__name__}' is required"
)
return init_value_dict
return model.parse_obj(_helper(model)) Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 7 replies
-
Hi Thomas class Child(BaseModel):
a: int = 1
class Parent(BaseModel):
x: int = 0
child: Child and you don't want to write? child: Child = Child() If that's the case I guess your solution works well and there is indeed no easier way afaik |
Beta Was this translation helpful? Give feedback.
-
Hi @PrettyWood, Thanks for the very helpful reply! I certainly agree it's far simpler in the case above to simply instantiate with a default as you've done. But my use case arose more in the context of a GenericModel that contains a submodel. Is there a way to call the cls constructor to instantiate a default in this setting? from typing import Generic, TypeVar
from pydantic import BaseModel
from pydantic.generics import GenericModel
class SubModelBase(BaseModel):
y: int = 11
class SubModelExtension(SubModelBase):
z: int = 12
Input = TypeVar("Input", bound=SubModelBase)
class MyModel(GenericModel, Generic[Input]):
submodel: Input # Cannot do = Input()
x: int = 10
if __name__ == "__main__":
print(default_initialize(MyModel[SubModelExtension])) |
Beta Was this translation helpful? Give feedback.
-
Hi @tfwillems Any news here? Your issue seems to be solved :) If it is please mark it as answered |
Beta Was this translation helpful? Give feedback.
Hi @PrettyWood,
Thanks for the very helpful reply! I certainly agree it's far simpler in the case above to simply instantiate with a default as you've done.
But my use case arose more in the context of a GenericModel that contains a submodel. Is there a way to call the cls constructor to instantiate a default in this setting?