This method prevents data validation
Read this by @Anime Bk:
https://stackoverflow.com/a/75011200
Solution with metaclasses
I’ve just come up with the following:
class AllOptional(pydantic.main.ModelMetaclass):
def __new__(cls, name, bases, namespaces, **kwargs):
annotations = namespaces.get('__annotations__', {})
for base in bases:
annotations.update(base.__annotations__)
for field in annotations:
if not field.startswith('__'):
annotations[field] = Optional[annotations[field]]
namespaces['__annotations__'] = annotations
return super().__new__(cls, name, bases, namespaces, **kwargs)
Use it as:
class UpdatedItem(Item, metaclass=AllOptional):
pass
So basically it replace all non optional fields with Optional
Any edits are welcome!
With your example:
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
import pydantic
app = FastAPI()
class Item(BaseModel):
name: str
description: str
price: float
tax: float
class AllOptional(pydantic.main.ModelMetaclass):
def __new__(self, name, bases, namespaces, **kwargs):
annotations = namespaces.get('__annotations__', {})
for base in bases:
annotations.update(base.__annotations__)
for field in annotations:
if not field.startswith('__'):
annotations[field] = Optional[annotations[field]]
namespaces['__annotations__'] = annotations
return super().__new__(self, name, bases, namespaces, **kwargs)
class UpdatedItem(Item, metaclass=AllOptional):
pass
# This continues to work correctly
@app.get("/items/{item_id}", response_model=Item)
async def get_item(item_id: int):
return {
'name': 'Uzbek Palov',
'description': 'Palov is my traditional meal',
'price': 15.0,
'tax': 0.5,
}
@app.patch("/items/{item_id}") # does using response_model=UpdatedItem makes mypy sad? idk, i did not check
async def update_item(item_id: str, item: UpdatedItem):
return item