[BUG] Response model validation doesn't work with `orm_mode = True` on all Pydantic attributes
See original GitHub issueTo Reproduce
- Create a file with:
from fastapi import FastAPI
from typing import List
from pydantic import BaseModel
app = FastAPI()
# Subscriptions
class SubscriptionCreate(BaseModel):
type: str = None
topic: str = None
class Subscription(SubscriptionCreate):
id: int = None
class Config:
orm_mode = True
# Create a post
@app.post("/subscriptions", response_model=List[Subscription])
def create_subscription(data: List[SubscriptionCreate]):
print(data)
return [5]
- Submit a POST request from Postman with this body:
[
{
"type": "email",
"topic": "books"
},
{
"type": "email",
"topic": "animals"
}
]
Actual behavior
No error and response is this:
[
{
"type": null,
"topic": null,
"id": null
}
]
Expected behavior
The error below is what I expect and I do get that if I remove class Config: orm_mode = True
from the model.
pydantic.error_wrappers.ValidationError: 1 validation error for Subscription
response -> 0
value is not a valid dict (type=type_error.dict)
Environment
- Windows 10
- Pydantic 1.4
- FastAPI 0.48.0
Issue Analytics
- State:
- Created 4 years ago
- Reactions:2
- Comments:6 (3 by maintainers)
Top Results From Across the Web
tiangolo/fastapi - Gitter
I have tried using this error class previously but it changes unexpectedly! David Montague. @dmontagu ?
Read more >Pydantic validation error field required in FastAPI
UserBase pydantic model contains sent_articles field that must have a list of dicts with "id": value. A validation error is: pydantic.
Read more >Models - pydantic
Initialisation of the object will perform all parsing and validation, if no ValidationError is raised, you know the resulting model instance is valid....
Read more >3.1. Pydantic Models - Python
Untrusted data can be passed to a model, and after parsing and validation pydantic guarantees that the fields of the resultant model instance...
Read more >SQL (Relational) Databases - FastAPI
FastAPI doesn't require you to use a SQL (relational) database. ... And with this, the Pydantic model is compatible with ORMs, and you...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
So, FastAPI doesn’t really ensure the response has some specific form, that’s not what the
response_model
really does.It uses the
response_model
to convert the data to that shape doing its “best-effort”. This is what allows you to return an ORM model for a User that could contain a hashed password, and then if theresponse_model
doesn’t include it, it will be filtered out, instead of raising an error.And
orm_mode
is just a way to tell Pydantic to be more permissive and try even harder. This is because ORM models don’t work likedict
s, their data can’t be extracted as would be from adict
. And even more, they don’t even behave like normal classes, if you dodir(some_model)
it will probably not contain the actual fields of the model. Because data is actually stored somewhere else, and access is done with getters and setters. And the specifics of this depend on each ORM. So, Pydantic just does its best to extract the data usinggetattr
which is the closest possible to the way ORMs expect to be used.In fact, Samuel Colvin doesn’t even like ORMs, he implemented
orm_mode
to allow those use cases and to simplify that for us, that lets us just return an ORM object (or list of ORM objects, etc). It is there only to try and serialize that data skipping private info and doing it with the best effort to save you from writing some extra lines everywhere converting your models to serialized data.But it is not really made to ensure your code is correct. That’s not its purpose. The fact that, if you return invalid data, it throws an error is more like a side effect of it. But if you enable
orm_mode
that just tells it “accept even weirder data from arbitrary ORM-like objects”.If you want to have
orm_mode
while still having more strict validations, the way to go would be to implement a customGetterDict
made exactly for your custom ORM, detecting if data is there or not, and detecting when it is an error that there’s no data and when not.The other option you have would be to serialize your models by hand and then make sure you are returning JSONable dicts and lists. But that’s probably not very fun.
Hmm, I’m not sure I get what you mean.
orm_mode
is the name of the setting, because it has to have some name 🤷 . But it doesn’t mean that it does something specific inferred by the config name.It accepts arbitrary class instances. To know exactly how it works, check the docs in Pydantic, on the section “ORM Mode (aka Arbitrary Class Instances)”: https://pydantic-docs.helpmanual.io/usage/models/#orm-mode-aka-arbitrary-class-instances
Pydantic actually uses
getattr
, so it doesn’t raise the attribute doesn’t exist.If you need to have some custom behavior in how your Pydantic models with
orm_mode
work, for example adding additional logic to check if you passed valid objects to them or you accidentally passed alist
ofint
, you can use aGetterDict
(explained in those same docs).