Skip to content

Conversation

nuno-andre
Copy link
Contributor

The ORM mode doesn't parse dictionaries if it's not explicitly called.

Change Summary

Prepend the orm_mode checking to the dict's.

Related issue number

Checklist

  • Unit tests for the changes exist
  • Tests pass on CI and coverage remains at 100%
  • Documentation reflects the changes where applicable
  • changes/<pull request or issue id>-<github username>.md file added describing change
    (see changes/README.md for details)

Example

from pydantic import BaseModel
from pydantic.utils import GetterDict

class Getter(GetterDict):
    # not relevant, just to show the behavior
    def get(self, key, default):
        key = key + key
        try:
            return self._obj[key]
        except TypeError:
            return getattr(self._obj, key, default)
        except KeyError:
            return default

class Model(BaseModel):
    class Config:
        orm_mode = True
        getter_dict = Getter

class ModelA(Model):
    a: int

class ModelB(Model):
    b: ModelA
from types import SimpleNamespace

x = dict(bb=SimpleNamespace(aa=1))
ModelB.from_orm(x)
#> b=ModelA(a=1)

y = dict(bb=dict(aa=1))
ModelB.from_orm(y)
#> ...
#> b -> a
#>   field required (type=value_error.missing)

Copy link
Collaborator

@PrettyWood PrettyWood left a comment

Choose a reason for hiding this comment

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

@nuno-andre Please update with tests and change file thanks

@PrettyWood PrettyWood added the awaiting author revision awaiting changes from the PR author label Jun 1, 2021
@nuno-andre
Copy link
Contributor Author

@PrettyWood Should I create a new test case or would you prefer I adapt test_custom_getter_dict_derived_model_class to check this condition?

https://github.com/samuelcolvin/pydantic/blob/c489445cea40c4962ecfa9e342eb30a0ba819129/tests/test_orm_mode.py#L271-L304

The _ORM mode_ doesn't parse dictionaries if it's not explicitly called.
@nuno-andre nuno-andre requested a review from PrettyWood June 4, 2021 16:48
@PrettyWood PrettyWood removed the awaiting author revision awaiting changes from the PR author label Sep 3, 2021
@PrettyWood PrettyWood merged commit 5549e8d into pydantic:master Sep 3, 2021
@PrettyWood
Copy link
Collaborator

Thank you!

@nuno-andre nuno-andre deleted the patch-1 branch September 4, 2021 00:07
@lsapan
Copy link

lsapan commented Sep 6, 2021

This change actually prevents models (that are ORM-enabled) from being initialized the normal way from dictionaries. Prior to this change, the following code worked:

from types import SimpleNamespace

from pydantic import BaseModel


class User(BaseModel):
    first_name: str
    last_name: str

    class Config:
        orm_mode = True


class State(BaseModel):
    user: User

    class Config:  # (The issue happens regardless of whether the outer class has orm_mode set)
        orm_mode = True


# Pass an "orm instance"
state = State.from_orm(SimpleNamespace(user=SimpleNamespace(first_name='John', last_name='Appleseed')))

# Pass dictionary data directly
state = State(**{'user': {'first_name': 'John', 'last_name': 'Appleseed'}})

After this change, the final line throws a validation error:

Traceback (most recent call last):
  File "/Users/luke/Developer/Clients/doctorschoice/flow/orm_issue.py", line 26, in <module>
    state = State(**{'user': {'first_name': 'John', 'last_name': 'Appleseed'}})
  File "/Users/luke/.pyenv/versions/flow/lib/python3.9/site-packages/pydantic/main.py", line 330, in __init__
    raise validation_error
pydantic.error_wrappers.ValidationError: 2 validation errors for State
user -> first_name
  field required (type=value_error.missing)
user -> last_name
  field required (type=value_error.missing)

This is actually a bit of an issue given the way FastAPI handles response models. During the processing of a request, it serializes the data, and then passes it through a response model (if one was provided) to make sure the response matches the desired output schema. If you're using an ORM-mode model for convenience (like one generated from Tortoise-ORM's pydantic_model_creator), it now crashes with a validation error.

Edit: I've opened an issue about this for the sake of organization - #3181

jpribyl pushed a commit to liquet-ai/pydantic that referenced this pull request Oct 7, 2021
The _ORM mode_ doesn't parse dictionaries if it's not explicitly called.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants