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

Access to orm_mode object in root validator #821

dmontagu opened this issue Sep 18, 2019 · 3 comments

Access to orm_mode object in root validator #821

dmontagu opened this issue Sep 18, 2019 · 3 comments


Copy link

dmontagu commented Sep 18, 2019

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

    def source_object(self):
        return self._obj

    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:
        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

    def orm_property(self) -> str:
        return "hello"

class MyModel(BaseModel):
    x: int
    y: str = Schema(None)

    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

# 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?

Copy link
Collaborator Author

dmontagu commented Sep 18, 2019

Also, it might make sense to change the name of GetterDict to OrmGetterDict if this is the only way it is used. (And maybe to OrmDict if it now supports setting, as above.)

Copy link

samuelcolvin commented Sep 20, 2019

Please review #822, I've tried to implement what you need a PR into the existing #817 PR.

Copy link

PrettyWood commented Dec 13, 2020

Closing the issue thanks to #822

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet

No branches or pull requests

3 participants