我正在学习FastAPI,并了解到使用pydantic进行数据验证是其功能之一.但是在从its tutorial开始阅读它的PUT方法示例后,我有一个问题,如果我只想让PUT主体包含更新的数据(因为URL已经有了它的id),我该怎么做呢?

使用教程中的示例代码作为我的意思的示例,

from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    id: str
    description:  str = "default description"
    price: Union[float, None] = None
    tax: float = 10.5
    tags: list[str] = []

...

@app.put("/items/{item_id}")
#async def update_item(item_id: str, item:Item):
async def update_item(item_id: str, item):
    pass

如果我编码async def update_item(item_id: str, item:Item),那么主体必须包含id属性,否则我将得到422"field Required".但我觉得这是不必要的,因为URL/items/{item_id}已经包含了ID,我只希望Body包含更新的数据.

但是当我编写async def update_item(item_id: str, item)代码时,令我惊讶的是,该项变成了required个查询参数!

正如其文件所示,

put with query parameters

那么为什么它会成为查询参数呢?这是我的第二个问题.

我觉得这是错误的,因为我更喜欢只查询GET的参数.

推荐答案

您需要使用一个模型作为父模型,该模型将包括在POSTPUT请求之间共享的所有属性,并拥有另一个模型,该模型将仅包含id属性并且继承自父模型,而不是BaseModel,并且用于POST个请求.下面的例子基于FastAPI's documentation中给出的例子.一些相关的答案可以在here找到.

工作示例

from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
from typing import Union, List

app = FastAPI()


class Item(BaseModel):
    description:  str = "default description"
    price: Union[float, None] = None
    tax: float = 10.5
    tags: List[str] = []
    

class ItemPost(Item):
    id: str


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Union[Item,str])
async def read_item(item_id: str):
    if item_id in items:
        return items[item_id]
    else:
        return 'Item not found'
    

@app.put("/items/{item_id}", response_model=Item)
async def update_item(item_id: str, item: Item):
    update_item_encoded = jsonable_encoder(item)
    items[item_id] = update_item_encoded
    return update_item_encoded
    

@app.post("/items")
async def create_item(item: ItemPost):
    new_item_encoded = jsonable_encoder(item)
    items[item.id] = new_item_encoded
    return 'Success'


As for the query parameters, the HTTP protocol does not prevent one from using query params when sending a request using PUT, POST, etc., methods. Hence, in FastAPI, when declaring a parameter that is not part of the path URL, e.g., item_id in the example above, or explicitly declared otherwise such as Item in the exmaple earler, it is automatically considered as query parameter of type str. Have a look at this answer and this answer for more details.

Python相关问答推荐

过载功能是否包含Support Int而不是Support Int?

通过仅导入pandas来在for循环中进行多情节

如何在图片中找到这个化学测试条?OpenCV精明边缘检测不会绘制边界框

ModuleNotFound错误:没有名为Crypto Windows 11、Python 3.11.6的模块

运行Python脚本时,用作命令行参数的SON文本

为什么sys.exit()不能与subproccess.run()或subprocess.call()一起使用

根据二元组列表在pandas中创建新列

无法使用requests或Selenium抓取一个href链接

Pandas计数符合某些条件的特定列的数量

Scrapy和Great Expectations(great_expectations)—不合作

joblib:无法从父目录的另一个子文件夹加载转储模型

无法连接到Keycloat服务器

为什么numpy. vectorize调用vectorized函数的次数比vector中的元素要多?

Maya Python脚本将纹理应用于所有对象,而不是选定对象

PYTHON、VLC、RTSP.屏幕截图不起作用

pandas:在操作pandora之后将pandora列转换为int

多个矩阵的张量积

如何在Django模板中显示串行化器错误

高效生成累积式三角矩阵

比较两个有条件的数据帧并删除所有不合格的数据帧