当前位置:   article > 正文

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

fastapi 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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

当不进行转码时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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述
这个操作不会返回一个包含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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

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

从结果看出当更新第三个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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述

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

闽ICP备14008679号