FastAPI学习-15.JSON 编码器 jsonable_encoder

发布时间 2023-09-17 10:57:29作者: 上海-悠悠

前言

在某些情况下,您可能需要将数据类型(如Pydantic模型)转换为与JSON兼容的数据类型(如dictlist等)。
比如,如果您需要将其存储在数据库中。
对于这种要求, FastAPI提供了jsonable_encoder()函数。

使用jsonable_encoder

jsonable_encoder

  • 在实际应用场景中,可能需要将数据类型(如:Pydantic 模型)转换为与 JSON 兼容的类型(如:字典、列表)
  • 比如:需要将数据存储在数据库中
  • 为此,FastAPI 提供了一个 jsonable_encoder() 函数
  • jsonable_encoder 实际上是 FastAPI 内部用来转换数据的,但它在许多其他场景中很有用

需求

  • 假设有一个仅接收兼容 JSON 数据的数据库 fake_db
  • 例如,它不接收日期时间对象,因为这些对象与 JSON 不兼容
  • 因此,必须将日期时间对象转换为包含 ISO 格式数据的 str
  • 同样,这个数据库不会接收 Pydantic 模型(具有属性的对象),只会接收 dict
  • 使用 jsonable_encoder 将数据转换成 dict

让我们假设你有一个数据库名为fake_db,它只能接收与 JSON 兼容的数据。

from datetime import datetime  
from typing import Union  
from fastapi import FastAPI  
from pydantic import BaseModel  
  
  
# 模拟数据库  
fake_db = {}  
  
  
class Item(BaseModel):  
    title: str  
    timestamp: datetime  
    description: Union[str, None] = None  
  
  
@app.post("/items/{pk}")  
def update_item(pk: str, item: Item):  
    # 新版2.x item.model_dump() 旧版1.x item.dict()  
    print(f"转成dict类型:{item.dict()}")  
    # 新版2.x item.model_dump_json() 旧版1.x item.json()  
    print(f"转成json类型:{item.json()}")  
    fake_db[pk] = item.dict()  
    print(f"得到数据:{fake_db}")  
    return fake_db

请求接口

POST http://127.0.0.1:8000/items/22 HTTP/1.1
User-Agent: Fiddler
Host: 127.0.0.1:8000
Content-Type: application/json
Content-Length: 86

{
  "title": 22,
  "timestamp": "2023-09-16 10:45:00",
  "description": "描述"
}

运行结果

转成dict类型:{'title': '22', 'timestamp': datetime.datetime(2023, 9, 16, 10, 45), 'description': '描述'}
转成json类型:{"title": "22", "timestamp": "2023-09-16T10:45:00", "description": "\u63cf\u8ff0"}
得到数据:{'22': {'title': '22', 'timestamp': datetime.datetime(2023, 9, 16, 10, 45), 'description': '描述'}}

Pydantic模型可以通过item.dict()转成字典对象 (**新版2.x item.model_dump() 旧版1.x item.dict() ** )

{'title': '22', 'timestamp': datetime.datetime(2023, 9, 16, 10, 45), 'description': '描述'}

由于 timestamp 是 datetime这类的对象,它不能通过json.dumps() 转成 json 对象。
我们想得到标准能转 json的 dict 格式,有 2 种实现方式

    1. item.json() 得到标准 json (**新版2.x item.model_dump_json() 旧版1.x item.json() **)。再使用json.loads()转字典
  • 2.使用jsonable_encoder

方法一:
可以通过

item.item.json()

得到json格式数据

{"title": "22", "timestamp": "2023-09-16T10:45:00", "description": "\u63cf\u8ff0"}

再使用json.loads()转字典

json.loads(item.json())

这样就可以得到可以转json的dict

{'title': '22', 'timestamp': '2023-09-16T10:45:00', 'description': '描述'}

方法二 :

使用fastapi 提供的 内置函数jsonable_encoder

from fastapi.encoders import jsonable_encoder


  
@app.post("/items/{pk}")  
def update_item(pk: str, item: Item):  
    json_item = jsonable_encoder(item)  
    print(f"jsonable_encoder: {json_item}")  
    fake_db[pk] = item.dict()  
    print(f"得到数据:{fake_db}")  
    return fake_db

运行结果

jsonable_encoder: {'title': '22', 'timestamp': '2023-09-16T10:45:00', 'description': '描述'}
得到数据:{'22': {'title': '22', 'timestamp': datetime.datetime(2023, 9, 16, 10, 45), 'description': '描述'}}

在这个例子中,它将Pydantic模型转换为dict,并将datetime转换为str
它将返回一个Python标准数据结构(例如dict),其值和子值都与JSON兼容。
调用它的结果后就可以使用 Python 标准编码中的 json.dumps()

jsonable_encoder实际上是FastAPI内部用来转换数据的。但是它在许多其他场景中也很有用。