# 请求体 - 更新数据 { #body-updates }
## 用 `PUT` 替换式更新 { #update-replacing-with-put }
更新数据可以使用 HTTP `PUT` 操作。
把输入数据转换为以 JSON 格式存储的数据(比如,使用 NoSQL 数据库时),可以使用 `jsonable_encoder`。例如,把 `datetime` 转换为 `str`。
{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
`PUT` 用于接收替换现有数据的数据。
### 关于替换的警告 { #warning-about-replacing }
用 `PUT` 把数据项 `bar` 更新为以下请求体时:
```Python
{
"name": "Barz",
"price": 3,
"description": None,
}
```
因为其中未包含已存储的属性 `"tax": 20.2`,输入模型会取 `"tax": 10.5` 的默认值。
因此,保存的数据会带有这个“新的” `tax` 值 `10.5`。
## 用 `PATCH` 进行部分更新 { #partial-updates-with-patch }
也可以使用 HTTP `PATCH` 操作对数据进行*部分*更新。
也就是说,你只需发送想要更新的数据,其余数据保持不变。
/// note | 注意
`PATCH` 没有 `PUT` 知名,也没那么常用。
很多团队甚至只用 `PUT` 实现部分更新。
你可以**随意**选择如何使用它们,**FastAPI** 不做任何限制。
但本指南会大致展示它们的预期用法。
///
### 使用 Pydantic 的 `exclude_unset` 参数 { #using-pydantics-exclude-unset-parameter }
如果要接收部分更新,建议在 Pydantic 模型的 `.model_dump()` 中使用 `exclude_unset` 参数。
比如,`item.model_dump(exclude_unset=True)`。
这会生成一个 `dict`,只包含创建 `item` 模型时显式设置的数据,不包含默认值。
然后再用它生成一个只含已设置(在请求中发送)数据、且省略默认值的 `dict`:
{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
### 使用 Pydantic 的 `update` 参数 { #using-pydantics-update-parameter }
接下来,用 `.model_copy()` 为已有模型创建副本,并传入 `update` 参数,值为包含更新数据的 `dict`。
例如,`stored_item_model.model_copy(update=update_data)`:
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
### 部分更新小结 { #partial-updates-recap }
简而言之,应用部分更新应当:
* (可选)使用 `PATCH` 而不是 `PUT`。
* 提取已存储的数据。
* 把该数据放入 Pydantic 模型。
* 生成不含输入模型默认值的 `dict`(使用 `exclude_unset`)。
* 这样只会更新用户实际设置的值,而不会用模型中的默认值覆盖已存储的值。
* 为已存储的模型创建副本,用接收到的部分更新数据更新其属性(使用 `update` 参数)。
* 把模型副本转换为可存入数据库的形式(比如,使用 `jsonable_encoder`)。
* 这类似于再次调用模型的 `.model_dump()` 方法,但会确保(并转换)值为可转换为 JSON 的数据类型,例如把 `datetime` 转换为 `str`。
* 把数据保存至数据库。
* 返回更新后的模型。
{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
/// tip | 提示
实际上,HTTP `PUT` 也可以使用同样的技巧。
但这里用 `PATCH` 举例,因为它就是为这种用例设计的。
///
/// note | 注意
注意,输入模型仍会被验证。
因此,如果希望接收的部分更新可以省略所有属性,则需要一个所有属性都标记为可选(带默认值或 `None`)的模型。
为了区分用于**更新**(全部可选)和用于**创建**(必填)的模型,可以参考[更多模型](extra-models.md){.internal-link target=_blank} 中介绍的思路。
///