python - 使用 Pydantic 将每个字段设为可选

标签 python python-3.x fastapi pydantic

我正在使用 FastAPI 和 Pydantic 制作 API。
我想要一些 PATCH 端点,可以一次编辑记录的 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 请求,我希望每个字段都是必需的。但是,在 PATCH 端点中,我不介意有效负载是否仅包含例如描述字段。这就是为什么我希望所有字段都是可选的。
幼稚的方法:
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 = {**annotations, **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__', {})
        print(bases)
        print(bases[0].__annotations__)
        for base in bases:
            annotations = {**annotations, **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

关于python - 使用 Pydantic 将每个字段设为可选,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67699451/

相关文章:

python - 如何在 Python 脚本中触发 Airflow DAG 运行?

Django Postgres JSONField 查询

Python:从 FTP 服务器检索多个文件

mongodb - 如何使用mongo db(Motor)实现fastapi的分页

python - numpy/python 中的加权平均值

python - numpy函数.fft.fft2()给出错误: “cannot do a non-empty take from an empty axis”(opencv,matplotlib,numpy,python27)

python - 有没有办法在 django html 文件中注释掉 python 代码?

python - 在 Python 中继续引用当前时间

python - 定义 Fastapi Pydantic 多对多关系

python - 带Redis的Python Fastapi示例