使用PYDANIC使每个字段都是可选的 [英] Make every fields as optional with Pydantic
本文介绍了使用PYDANIC使每个字段都是可选的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我正在使用FastAPI和Pydtic制作一个API。
我希望有一些补丁端点,其中一条记录的1个或N个字段可以一次编辑。此外,我希望客户端仅传递负载中的必需字段。示例:
class Item(BaseModel):
name: str
description: str
price: float
tax: float
@app.post("/items", response_model=Item)
async def post_item(item: Item):
...
@app.patch("/items/{item_id}", response_model=Item)
async def update_item(item_id: str, item: Item):
...
在本例中,对于POST请求,我希望每个字段都是必填的。然而,在补丁端点中,我并不介意有效负载是否只包含描述字段。这就是我希望所有字段都为可选的原因。
幼稚的做法:
class UpdateItem(BaseModel):
name: Optional[str] = None
description: Optional[str] = None
price: Optional[float] = None
tax: Optional[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
所以基本上它将所有非可选字段替换为Optional
欢迎任何编辑!
使用您的示例:
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}") # not using response_model=Item
async def update_item(item_id: str, item: UpdatedItem):
return item
这篇关于使用PYDANIC使每个字段都是可选的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文