当前位置: 首页 > article >正文

三周精通FastAPI:19 Body - Updates 请求体 - 更新数据

官网文档:https://fastapi.tiangolo.com/zh/tutorial/body-updates/

请求体 - 更新数据¶

用 PUT 更新数据¶

更新数据请用 HTTP PUT 操作。把输入数据转换为以 JSON 格式存储的数据(比如,使用 NoSQL 数据库时),可以使用 jsonable_encoder。例如,把 datetime 转换为 str

from typing import List, Union

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

app = FastAPI()


class Item(BaseModel):
    name: Union[str, None] = None
    description: Union[str, None] = None
    price: Union[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)
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

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

关于更新数据的警告¶

用 PUT 把数据项 bar 更新为以下内容时:

{ "name": "Barz", "price": 3, "description": None, }

因为上述数据未包含已存储的属性 "tax": 20.2,新的输入模型会把 "tax": 10.5 作为默认值。

因此,本次操作把 tax 的值「更新」为 10.5

用 PATCH 进行部分更新¶

HTTP PATCH 操作用于更新 部分 数据。

即,只发送要更新的数据,其余数据保持不变。

"笔记"

PATCH 没有 PUT 知名,也怎么不常用。

很多人甚至只用 PUT 实现部分更新。

FastAPI 对此没有任何限制,可以随意互换使用这两种操作。

但本指南也会分别介绍这两种操作各自的用途。

使用 Pydantic 的 exclude_unset 参数¶

更新部分数据时,可以在 Pydantic 模型的 .dict() 中使用 exclude_unset 参数。

比如,item.dict(exclude_unset=True)

这段代码生成的 dict 只包含创建 item 模型时显式设置的数据,而不包括默认值。然后再用它生成一个只含已设置(在请求中所发送)数据,且省略了默认值的 dict

@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

使用 Pydantic 的 update 参数¶

接下来,用 .copy() 为已有模型创建调用 update 参数的副本,该参数为包含更新数据的 dict。例如,stored_item_model.copy(update=update_data)

    updated_item = stored_item_model.copy(update=update_data)

更新部分数据小结¶

简而言之,更新部分数据应:

  • 使用 PATCH 而不是 PUT (可选,也可以用 PUT);
  • 提取存储的数据;
  • 把数据放入 Pydantic 模型;
  • 生成不含输入模型默认值的 dict (使用 exclude_unset 参数);
    • 只更新用户设置过的值,不用模型中的默认值覆盖已存储过的值。
  • 为已存储的模型创建副本,用接收的数据更新其属性 (使用 update 参数)。
  • 把模型副本转换为可存入数据库的形式(比如,使用 jsonable_encoder)。
    • 这种方式与 Pydantic 模型的 .dict() 方法类似,但能确保把值转换为适配 JSON 的数据类型,例如, 把 datetime 转换为 str 。
  • 把数据保存至数据库;
  • 返回更新后的模型。
 
@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

"提示"

实际上,HTTP PUT 也可以完成相同的操作。 但本节以 PATCH 为例的原因是,该操作就是为了这种用例创建的。

"笔记"

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

因此,如果希望接收的部分更新数据可以省略其他所有属性,则要把模型中所有的属性标记为可选(使用默认值或 None)。

为了区分用于更新所有可选值的模型与用于创建包含必选值的模型,请参照更多模型 一节中的思路。

 

实践

用PATCH进行部分更新。

源代码

将代码写入bodyupdates.py文件

from typing import List, Union

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

app = FastAPI()


class Item(BaseModel):
    name: Union[str, None] = None
    description: Union[str, None] = None
    price: Union[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

启动服务

uvicorn bodyupdates:app --reload

测试

 先用get浏览下:

curl 127.0.0.1:8000/items/bar
{"name":"Bar","description":"The bartenders","price":62.0,"tax":20.2,"tags":[]}

通过PATCH更新字段:

curl -X PATCH "http://127.0.0.1:8000/items/bar" -H "Content-Type: application/json" -d '{"description": "Updated description", "price": 70.0}'

执行更新的输出:

{"name":"Bar","description":"Updated description","price":70.0,"tax":20.2,"tags":[]}

可见确实更改了Bar的price数值。


http://www.kler.cn/a/369680.html

相关文章:

  • 数仓ETL测试
  • 低代码产品插件功能一览
  • 力扣【1049. 最后一块石头的重量 II】Java题解(背包问题)
  • 从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(绘图设备封装)
  • python:斐索实验(Fizeau experiment)
  • ODP(OBProxy)路由初探
  • 【GeekBand】C++设计模式笔记9_Abstract Factory_抽象工厂
  • 如何让Nginx更安全?
  • css绘制s型(grid)
  • 【Linux学习】(8)第一个Linux编程进度条程序|git三板斧
  • 静态局部变量
  • 深入RAG:知识密集型NLP任务的解决方案
  • 路由守卫重定向页面
  • vxe-table 表格中使用输入框、整数限制、小数限制,单元格渲染数值输入框
  • 雷军救WPS“三次”,WPS注入新生力量,不再“抄袭”微软
  • Kubernetes(K8S) + Harbor + Ingress 部署 SpringBoot + Vue 前后端分离项目
  • WPF+MVVM案例实战(一)- 设备状态LED灯变化实现
  • 【Rust练习】18.特征 Trait
  • Puppeteer 与浏览器版本兼容性:自动化测试的最佳实践
  • Javaee---多线程(一)
  • ubuntu系统
  • 重写(外壳不变)
  • Linux下的文件系统(进程与文件)
  • Spring Cloud Alibaba实战入门之Nacos注册中心(四)
  • 青少年编程与数学 02-002 Sql Server 数据库应用 16课题、安全机制
  • HardLockUp