前面记录的是路径参数和查询参数的内容,那两种形式的数据都不算的发送的数据,都是存在路径中的数据,请求体是客户端发给接口的参数,不存在于路径中,本文就主要记录FastAPI中的请求体应用内容。

一个发送请求体的接口

# 创建一个数据模型
class Animal(BaseModel):
    name:str
    category:Optional[str] = None
    age:int

# 模型声明为请求体参数
@app03.post("/stu03/responsebody/")
async def stu03_responsebody(animal:Animal):
    return animal.dict()

首先定义一个基本模型,是基于Pydantic的,然后将接口的animal参数声明为Animal类型的参数,接口接收请求体后返回给客户端接收的请求体内容

image-20221125221850643

同时声明请求体、路径参数、查询参数

@app03.put("/stu03/blend/{param}")
async def stu03_param_blend(
        respose_param: Animal,
        param:int = Path(default=52),
        query_param:Optional[str] = None
):
    return {"respose_param":respose_param,"param":param,"query_param":query_param}

上面的代码就声明了三个参数respose_paramparamquery_param,分布代表请求体、路径参数、查询参数

  • 如果在路径中也声明了该参数,它将被用作路径参数。
  • 如果参数属于单一类型(比如 intfloatstrbool 等)它将被解释为查询参数。
  • 如果参数的类型被声明为一个 Pydantic 模型,它将被解释为请求体

image-20221125222104993

请求体中嵌套多个参数

# 创建一个数据模型
# 使用 Pydantic 的 Field 在 Pydantic 模型内部声明校验和元数据。
class City(BaseModel):
    country:str = "中国"
    provence:str = Field(...,example = "四川") # Field可以定义请求体的格式和类型
    citys: Optional[List] = None
    population: int = Field(default=None,title="人口数",ge=1000)

# 请求体中多个参数
@app03.put("/stu03/morebody")
def stuo3_morebody(
        animal:Animal, # 最开始定义的模型
        city:City
):
    return {"animal":animal,"city":city}

上面的请求体就包含两个参数,分别是AnimalCity,请求体如下:

{
  "animal": {
    "name": "string",
    "category": "string",
    "age": 0
  },
  "city": {
    "country": "中国",
    "provence": "四川",
    "citys": [
      "string"
    ],
    "population": 1000
  }
}

请求体中嵌入单一类型参数

@app03.post("/stu03/importance")
def stu03_importance(
        importance_param_int_query: int,
        importance_param_int:int = Body(default=12)
):
    return {"importance_param_int":importance_param_int,"importance_param_int_query":importance_param_int_query}

同时声明请求体、路径参数、查询参数一节所述,如果有单一类型的参数,那么他将会被解析为查询参数,所以要将单一类型的参数嵌套进入请求体,就需要使用 Body 指示 FastAPI 将其作为请求体的另一个键进行处理;

如上述代码,importance_param_int_query会被解析为查询参数,而importance_param_int会被嵌套进入请求体;

image-20221125223533641

请求体中嵌入单一参数

@app03.post("/stu03/oneparam")
def stuo3_oneparam(
        param:City = Body(embed=True)
):
    return param

与上一步不同,上一步是单一类型的参数,这里是单一参数,即只有一个参数,这个参数是自定义的模型类类型参数;

处理和不处理的区别就是请求体中是否会有参数名作为键,描述抽象的话,看下面的对比就好;

使用方法就是将Bodyembed参数设为True即可;

# 设置过的
{
  "param": {
    "country": "中国",
    "provence": "四川",
    "citys": [
      "string"
    ],
    "population": 1000
  }
}
# 未设置的
{
  "country": "中国",
  "provence": "四川",
  "citys": [
    "string"
  ],
  "population": 1000
}

参数多层嵌套

class CityDevelop(BaseModel):
    city:City
    money:int = 666
    campony:int = 888

class CityDevelopTarget(BaseModel):
    citydevelop:CityDevelop
    metro:int = 20
    gdp:int = 50000


@app03.post("/stu03/multiple_param")
def stu03_multiple_param(
        citydeveloptarget:CityDevelopTarget
):
    return citydeveloptarget

这里CityDevelop嵌套了请求体中嵌套多个参数中的City模型,CityDevelopTarget嵌套了CityDevelop模型,请求体如下:

{
  "citydevelop": {
    "city": {
      "country": "中国",
      "provence": "四川",
      "citys": [
        "string"
      ],
      "population": 1000
    },
    "money": 666,
    "campony": 888
  },
  "metro": 20,
  "gdp": 50000
}

纯列表的请求体

@app03.post("/stu03/bodylist")
def stu03_body_list(
        ListCity:List[City]
):
    return ListCity

如果需要请求体最外层是一个列表,直接在对应函数中声明类型即可ListCity:List[City]

如果是多个参数,目前想到的办法就是先声明一个模型类进行嵌套了,没有找到什么方法或者函数;

[
  {
    "country": "中国",
    "provence": "四川",
    "citys": [
      "string"
    ],
    "population": 1000
  }
]

源码

# -*- coding: utf-8 -*-
# @Time: 2022/11/25 16:47
# @Author: MinChess
# @File: stu03.py
# @Software: PyCharm
from fastapi import APIRouter,Path,Body
from pydantic import BaseModel,Field

from typing import List,Optional

app03 = APIRouter()

# 创建一个数据模型
class Animal(BaseModel):
    name:str
    category:Optional[str] = None
    age:int

# 模型声明为请求体参数
@app03.post("/stu03/responsebody/")
async def stu03_responsebody(animal:Animal):
    return animal.dict()

# 请求体 + 路径参数 + 查询参数
@app03.put("/stu03/blend/{param}")
async def stu03_param_blend(
        respose_param: Animal,
        param:int = Path(default=52),
        query_param:Optional[str] = None
):
    return {"respose_param":respose_param,"param":param,"query_param":query_param}

# 创建一个数据模型
# 使用 Pydantic 的 Field 在 Pydantic 模型内部声明校验和元数据。
class City(BaseModel):
    country:str = "中国"
    provence:str = Field(...,example = "四川") # Field可以定义请求体的格式和类型
    citys: Optional[List] = None
    population: int = Field(default=None,title="人口数",ge=1000)

# 请求体中多个参数
@app03.put("/stu03/morebody")
def stuo3_morebody(
        animal:Animal,
        city:City
):
    return {"animal":animal,"city":city}

# 请求体中嵌入单一值
@app03.post("/stu03/importance")
def stu03_importance(
        importance_param_int_query: int,
        importance_param_int:int = Body(default=12)
):
    return {"importance_param_int":importance_param_int,"importance_param_int_query":importance_param_int_query}

# 请求体中嵌入单一参数
@app03.post("/stu03/oneparam")
def stuo3_oneparam(
        param:City = Body(embed=True)
):
    return param

# 单一参数未在请求体中嵌入
@app03.post("/stu03/notoneparam")
def stuo3_notoneparam(
        param:City
):
    return param
# 多层嵌套
class CityDevelop(BaseModel):
    city:City
    money:int = 666
    campony:int = 888

class CityDevelopTarget(BaseModel):
    citydevelop:CityDevelop
    metro:int = 20
    gdp:int = 50000


@app03.post("/stu03/multiple_param")
def stu03_multiple_param(
        citydeveloptarget:CityDevelopTarget
):
    return citydeveloptarget

# 纯列表请求体
@app03.post("/stu03/bodylist")
def stu03_body_list(
        ListCity:List[City],
        ListCityDevelop:List[CityDevelop]
):
    return ListCity,ListCityDevelop