-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Closed
Labels
Description
Feature Request
It would be nice if you could access the "source" object in a root_validator (coming soon; see #817) when the model was being initialized via a call to from_orm. This would enable almost any form of custom loading from an orm object possible by use of a root validator.
I think this can be accomplished now by making changes only to the GetterDict class:
class GetterDict:
"""
Hack to make object's smell just enough like dicts for validate_model.
"""
__slots__ = ('_obj', '_overrides')
def __init__(self, obj: Any):
self._obj = obj
self._overrides: Optional[Dict] = None # NEWLY ADDED
# NEWLY ADDED
def source_object(self):
return self._obj
# NEWLY ADDED
def __setitem__(self, key, value):
if self._overrides is None:
self._overrides = {}
self._overrides.__setitem__(key, value)
def get(self, item: Any, default: Any) -> Any:
# SLIGHTLY MODIFIED
if self._overrides is None:
# This check could be removed if we make the _overrides non-optional
# but I think that would come with a *slightly* larger performance penalty if not used
return getattr(self._obj, item, default)
return self._overrides.get(item) or getattr(self._obj, item, default)
def keys(self) -> Set[Any]:
"""
We don't want to get any other attributes of obj if the model didn't explicitly ask for them
"""
return set()The only performance sacrifice if not making use of the feature is the check if self._overrides is None (it seems to me like the impact would be miniscule in practice).
This would allow things like:
from pydantic import BaseModel, Schema, root_validator
from pydantic.utils import GetterDict
class MyModelORM:
def __init__(self, x):
self.x = x
@property
def orm_property(self) -> str:
return "hello"
class MyModel(BaseModel):
x: int
y: str = Schema(None)
@root_validator(pre=True)
def get_y(cls, values):
if isinstance(values, GetterDict):
# This is how you know it got called via from_orm
values['y'] = values.source_object().orm_property
return values
class Config:
orm_mode = True
print(MyModel.from_orm(MyModelORM(x=1)))
# MyModel x=1 y='hello'@samuelcolvin I can't think of any breaking changes this would introduce, can you? Would this be interesting to you?