当前位置:   article > 正文

23_请求体--更新数据_fastapi 请求体

fastapi 请求体

23_请求体–更新数据

1. 使用PUT更新数据

如果想要更新一个存储的item,可以使用 HTTP PUT 操作。

我们可以使用jsonable_encoder()将输入数据转换为可以作为JSON存储的数据(如,保存在NoSQL数据库中的数据)。如,将datetime转换为str

# python3.10
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str | None = None
    description: str | None = None
    price: float | None = None
    tax: float = 10.5
    tags: list[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=Item)
async def read_item(item_id: str):
    return items[item_id]


@app.put("/items/{item_id}", response_model=Item)  # 使用PUT请求更新数据
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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

PUT用于接收替换现有数据的新数据。

关于替换数据的警告

如果我们想使用下面的新请求体数据通过PUT更新之前的bar item:

{
    "name": "Barz",
    "price": 3,
    "description": None,
}
  • 1
  • 2
  • 3
  • 4
  • 5

因为新的请求体中不包含之前item中储存的"tax": 20.2属性,新的输入模型会将"tax": 10.5作为默认值。

所以更新后的数据中的"tax"的值为10.5


2. 使用PATCH进行部分更新

我们还可以使用HTTP PATCH操作对数据进行部分更新。这样我们可以只发送我们想要更新的数据,其他数据保持不变。

注意:
PATCH 相比于 PUT 不怎么知名,使用也比较少。
很多人甚至在使用时只用PUT来进行部分更新。
不过,我们可以自由选择使用哪种方式,FastAPI不会进行强制限制。
但是本指南或多或少地向您展示了它们是如何被使用的。

2.1 使用 Pydantic 的 exclude_unset 参数

如果我们想要接收部分更新,使用 Pydantic model 的.dict()方法提供的exclude_unset 参数会很有用。像这样:item.dict(exclude_unset=True)

这会生成一个dict,其中只包含创建 item model 时显示设置的数据,而不会包含默认值。

然后再用它生成一个只含已设置(在请求中所发送)数据,且省略了默认值的 dict:

# python3.10
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str | None = None
    description: str | None = None
    price: float | None = None
    tax: float = 10.5
    tags: list[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=Item)
async def read_item(item_id: str):
    return items[item_id]


@app.patch("/items/{item_id}", response_model=Item)  # 使用PATCH请求进行部分更新
async def update_item(item_id: str, item: Item):
    stored_item_data = items[item_id]
    stored_item_model = Item(**stored_item_data)
    update_data = item.dict(exclude_unset=True)  # 设置exclude_unset
    updated_item = stored_item_model.copy(update=update_data)
    items[item_id] = jsonable_encoder(updated_item)
    return updated_item
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

2.2 使用Pydantic 的update参数

然后,先使用.copy()创建一个已有model的拷贝,然后通过update参数传入包含要更新数据的dict

像这样:sorted_item_model.copy(update=update_data):

#python3.10
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str | None = None
    description: str | None = None
    price: float | None = None
    tax: float = 10.5
    tags: list[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=Item)
async def read_item(item_id: str):
    return items[item_id]


@app.patch("/items/{item_id}", response_model=Item)
async def update_item(item_id: str, item: Item):
    stored_item_data = items[item_id]
    stored_item_model = Item(**stored_item_data)
    update_data = item.dict(exclude_unset=True)
    updated_item = stored_item_model.copy(update=update_data)  # 复制并使用update参数更新数据
    items[item_id] = jsonable_encoder(updated_item)
    return updated_item
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

2.3 部分更新小结

总结,想要部分更新数据应该通过以下方式进行:

  • (可选)使用PATCH请求代替PUT
  • 读取出已经存储的数据;
  • 将数据放入 Pydantic model;
  • 生成不包含输入模型默认值的dict(通过exclude_unset参数);
    • 这种方式可以只更新用户设置的值,不使用model的默认值覆盖已经存储过的值;
  • 为已存储的model创建拷贝,用接收的数据部分更新其属性(使用 update参数);
  • 把model的拷贝转换为可存入数据库的形式(如,使用jsonable_encoder)
    • 这与Pydantic model 的 .dict()方法类似,但能确保把值转换为兼容JSON的数据类型。如,将datetime转换为str
  • 将数据保存到数据库中
  • 返回更新后的model
#python3.10
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str | None = None
    description: str | None = None
    price: float | None = None
    tax: float = 10.5
    tags: list[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=Item)
async def read_item(item_id: str):
    return items[item_id]

// 部分更新数据操作
@app.patch("/items/{item_id}", response_model=Item)
async def update_item(item_id: str, item: Item):
    stored_item_data = items[item_id]
    stored_item_model = Item(**stored_item_data)
    update_data = item.dict(exclude_unset=True)
    updated_item = stored_item_model.copy(update=update_data)
    items[item_id] = jsonable_encoder(updated_item)
    return updated_item
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

提示:

实际上我们可以通过HTTP PUT来完成相同的操作。不过在实例中使用了PATCH,因为它就是用来做部分更新的。

注意:

注意,输入模型仍需验证。

所以,如果你想要接收可以省略所有属性的部分更新,则需要一个将所有属性标记为可选的model(使用默认值或 None)。

为了区分具有更新所需的所有可选值的模型和具有创建所需值的模型,您可以使用额外模型中描述的思想。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/416548
推荐阅读
相关标签
  

闽ICP备14008679号