7.FastAPI嵌套请求体
在FastAPI中, Pydantic支持任意深度的嵌套模型,同时支持校验和文档。
7.1List字段
7.1.1使用 Python list 定义字段类型
代码如下:
from fastapi import FastAPI app = FastAPI() @app.post(path='/sort') async def sort(lst: list): lst.sort() return lst
执行请求:
curl -H "Content-Type: application/json" -X POST -d "[10,2,3,9,8,5,6,7,1,4]" http://127.0.0.1:8000/sort [1,2,3,4,5,6,7,8,9,10]
7.1.2使用 Python 标准库 的typing模块中的List
在上面的代码中,使用了Python的list类型定义参数的类型,但这样做无法指定元素的类型,也就是说,参数可以时任意类型的列表;如果使用Python 标准库的typing模块中的List,则可以指定List的子类型来限制元素的类型;代码如下:
from fastapi import FastAPI from typing import List app = FastAPI() @app.post(path='/sort') async def sort(lst: List[str]): lst.sort() return lst
代码中,将lst的类型设置为typing模块的List类型,并限制子类型为str,执行请求:
curl -H "Content-Type: application/json" -X POST -d "[10,2,3,9,8,5,6,7,1,4]" http://127.0.0.1:8000/sort ["1","10","2","3","4","5","6","7","8","9"]
可以看到:返回的列表为字符串列表,并且是按照字符串的排序规则进行排序的。
上面的规则同样适用于set、tuple、dict等,在此不再一一举例。
7.2嵌套模型
Pydantic 模型的每个属性都可以声明类型,类型本身也可以是另外一个 Pydantic 模型,所以,可以声明拥有特定属性名称、类型和校验的深度嵌套的 JSON 对象。
代码示例:
from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Cuboid(BaseModel): length: int width: int high: int class Box(BaseModel): sn: int name: str cubiod: Cuboid @app.post(path='/box') async def sort(box: Box): return {'box': box, 'volume': box.cubiod.length * box.cubiod.width * box.cubiod.high}
执行请求:
curl -H "Content-Type: application/json" -X POST -d "{\"sn\":1, \"name\":\"box1\", \"cubiod\":{\"length\": 10,\"width\": 10,\"high\": 10}}" http://127.0.0.1:8000/box { "box":{ "sn":1, "name":"box1", "cubiod":{ "length":10, "width":10, "high":10 } }, "volume":1000 }
在上面的代码中,模型Cuboid是模型Box的子模型。
7.3子模型列表
代码示例:
from fastapi import FastAPI from pydantic import BaseModel from typing import List from statistics import mean app = FastAPI() class Cuboid(BaseModel): length: int width: int high: int class Box(BaseModel): sn: int name: str cubiods: List[Cuboid] @app.post(path='/box') async def sort(box: Box): volumes = [] for cubiod in box.cubiods: volumes.append(cubiod.length * cubiod.width * cubiod.high) return { 'box': box, 'min_volume': min(volumes), 'max_volume': max(volumes), 'sum_volume': sum(volumes), 'avg_volume': mean(volumes) }
执行请求:
curl -H "Content-Type: application/json" -X POST -d "{\"sn\":1, \"name\":\"boxes1\", \"cubiods\":[{\"length\": 10,\"width\": 10,\"high\": 10}, {\"length\": 9,\"width\": 9,\"high\": 9}, {\"length\": 8,\"width\": 8,\"high\": 8}]}" http://127.0.0.1:8000/box { "box":{ "sn":1, "name":"boxes1", "cubiods":[ { "length":10, "width":10, "high":10 },{ "length":9, "width":9, "high":9 }, "length":8, "width":8, "high":8 } ] }, "min_volume":512, "max_volume":1000, "sum_volume":2241, "avg_volume":747 }
7.4任意 dict 请求体
在FastAPI中,可以将请求体声明为使用某类型的键和某类型值的 dict,也就是说,不需要事先确定字段名称,当需要接收未知键的dict时,非常有用。
需要注意: JSON 仅支持将 str 作为键,所以当需要使用int等非str类型作为键时,Pydantic 具有自动转换数据的功能。也就是说,即使API 客户端只能将字符串作为键发送,只要这些字符串内容仅包含整数,Pydantic 就会对其进行int转换并校验。
代码示例:
from fastapi import FastAPI from typing import Dict app = FastAPI() @app.post(path='/dictionary') async def dictionary(d: Dict[int, str]): return {'key': list(d.keys()), 'value': list(d.values())}
执行请求:
curl -H "Content-Type: application/json" -X POST -d "{\"1\":\"First\"}" http://127.0.0.1:8000/dictionary {"key":[1],"value":["First"]}
通过上面的代码,可以看到,路由接收以int为键,以str为值的字典,客户端请求时,传入的键类型为str,但该str是可以转换为int类型的字符串。