fastapi_No.10_JSON兼容编码器和请求体更新数据

JSON兼容编码器

在某些情况下,可能需要将数据类型(如Pydantic模型)转换为与JSON兼容的数据类型(如dict、list等),对于这种要求,fastapi提供了jsonable_encoder()函数。

不兼容示例

from datetime import datetime
from typing import Union
from fastapi import FastAPI
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel
fake_db = {}
class Item(BaseModel):
    title: str
    timestamp: datetime
    description: Union[str, None] = None
app = FastAPI()
# 演示不使用jsonable_encoder编码
@app.post("/items/{id}")
def insert_item(id: str, item: Item):
    fake_db[id] = item
    print(fake_db) 
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app="main:app",host="127.0.0.1",port=8080,reload=True)

当不进行转码时fake_db中存储的内容类似下图:
一个类带属性的,默认输出格式。
在这里插入图片描述

兼容示例

# 演示使用jsonable_encoder编码
@app.put("/items/{id}")
def update_item(id: str, item: Item):
    json_compatible_item_data = jsonable_encoder(item)
    fake_db[id] = json_compatible_item_data
    print(fake_db)

在这里插入图片描述
这个操作不会返回一个包含JSON格式(作为字符串)数据的庞大的str。它将返回一个Python标准数据结构(例如dict),其值和子值都与JSON兼容。

请求体更新数据

fastapi中通常使用put或patch两种方法来更新数据。两者可以进行互换,通常更新全部数据用PUT,更新部分数据用PATCH。

引出更新数据时应注意的问题

当数据模型中存在默认值时,如果直接利用这个模型更新数据,会产生意想不到的结果。
后端代码如下:

#  演示更新数据时默认值产生的后果
class Student(BaseModel):
    name:Union[str,None] = None
    description:Union[str,None] = None
    sex:Union[str,None]=None
    age:int = 18
    hobby:List[str] = []
# 模拟目前存在的一些学生信息
students = [
    {"name":"jack","age":20},
    {"name":"tom","description":"he is a boy","sex":"male"},
    {"name":"jerry","hobby":["basketball","games"]}
]
# 定义路径装饰器和路径操作函数来更新某个student信息
@app.patch("/students/{id}")
async def update_student(id:int,stu:Student):
    if id<len(students):
        students[id]=jsonable_encoder(stu)
    else:
        raise HTTPException(status_code=404,detail="out of range")
    return students

测试结果:
在这里插入图片描述

从结果看出当更新第三个student的年龄时,由于只输入了age字段,其他字段默认为None或[]。在默认情况下更新时,默认值会参与更新,导致原来jerry同学的name,hobby字段的信息丢失。

解决更新时默认值问题

主要是利用BaseModel子类的copy函数的update参数和dict函数中的exclude_unset参数,来解决这个问题。
后端代码如下:

# 演示通过BaseModel子类的dict函数的exclude_unset参数解决此类问题
@app.put("/students/{id}")
async def update_student(id:int,stu:Student):
    if id<len(students):
        # 第一步:取出原存储的数据
        stu_stored = students[id]
        # 第二步:根据原存储数据创建原数据的数据模型对象
        stu_model = Student(**stu_stored)
        # 第三步:利用BaseModel子类的dict函数的exclude_unset参数取出改变的字段字典
        update_data = stu.dict(exclude_unset=True)
        # 第四步:利用BaseModel子类的copy函数的update参数更新指定字段数据
        update_item = stu_model.copy(update=update_data)
        # 第五步:用更新后的数据对象替换原数据对象,完成更换
        students[id]=jsonable_encoder(update_item)
    else:
        raise HTTPException(status_code=404,detail="out of range")
    return students

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱学习_程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值