Repository: pydantic/pydantic

Issue:
Nested ORM-mode models can no longer be initialized from nested dictionaries
### Checks

* [x] I added a descriptive title to this issue
* [x] I have searched (google, github) for similar issues and couldn't find anything
* [x] I have read and followed [the docs](https://pydantic-docs.helpmanual.io/) and still think this is a bug

# Bug

I mentioned this as a comment on https://github.com/samuelcolvin/pydantic/pull/2718 but since it's already merged I figured I should open an issue.

#2718 actually prevents models (that are ORM-enabled) from being initialized the normal way from dictionaries. Prior to that change, the following code worked:

```python
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


# 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 that 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.


Comments:
Thanks for reporting!
I'm so glad to have people messing around with `master`!
It's always a great way to catch things beforehand 😄 

Patch:
diff --git a/pydantic/main.py b/pydantic/main.py
--- a/pydantic/main.py
+++ b/pydantic/main.py
@@ -656,10 +656,10 @@ def validate(cls: Type['Model'], value: Any) -> 'Model':
 
         value = cls._enforce_dict_if_root(value)
 
-        if cls.__config__.orm_mode:
-            return cls.from_orm(value)
-        elif isinstance(value, dict):
+        if isinstance(value, dict):
             return cls(**value)
+        elif cls.__config__.orm_mode:
+            return cls.from_orm(value)
         else:
             try:
                 value_as_dict = dict(value)
@@ -669,6 +669,8 @@ def validate(cls: Type['Model'], value: Any) -> 'Model':
 
     @classmethod
     def _decompose_class(cls: Type['Model'], obj: Any) -> GetterDict:
+        if isinstance(obj, GetterDict):
+            return obj
         return cls.__config__.getter_dict(obj)
 
     @classmethod


Test patch:
diff --git a/tests/test_orm_mode.py b/tests/test_orm_mode.py
--- a/tests/test_orm_mode.py
+++ b/tests/test_orm_mode.py
@@ -1,3 +1,4 @@
+from types import SimpleNamespace
 from typing import Any, Dict, List
 
 import pytest
@@ -305,15 +306,14 @@ class Config:
 
 
 def test_recursive_parsing():
-    from types import SimpleNamespace
-
     class Getter(GetterDict):
         # try to read the modified property name
         # either as an attribute or as a key
         def get(self, key, default):
             key = key + key
             try:
-                return self._obj[key]
+                v = self._obj[key]
+                return Getter(v) if isinstance(v, dict) else v
             except TypeError:
                 return getattr(self._obj, key, default)
             except KeyError:
@@ -337,3 +337,24 @@ class ModelB(Model):
     # test recursive parsing with dict keys
     obj = dict(bb=dict(aa=1))
     assert ModelB.from_orm(obj) == ModelB(b=ModelA(a=1))
+
+
+def test_nested_orm():
+    class User(BaseModel):
+        first_name: str
+        last_name: str
+
+        class Config:
+            orm_mode = True
+
+    class State(BaseModel):
+        user: User
+
+        class Config:
+            orm_mode = True
+
+    # Pass an "orm instance"
+    State.from_orm(SimpleNamespace(user=SimpleNamespace(first_name='John', last_name='Appleseed')))
+
+    # Pass dictionary data directly
+    State(**{'user': {'first_name': 'John', 'last_name': 'Appleseed'}})