赞
踩
在某些情况下,可能需要将数据类型(如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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。