第6节,FastAPI解析POST请求体

1. 解析json格式数据

我们先讨论POST请求的content-type 为 application/json的情况,json是比较流行和通用的API接口交互数据的格式。

FastAPI解析json格式数据,使用的是Pydantic,它是一种常用的用于数据接口schema定义与检查的库,你需要定义数据的Model

from typing import Optional
from pydantic import BaseModel
from fastapi import FastAPI

app = FastAPI()

class User(BaseModel):
    name: str       # 姓名
    age: int        # 年龄
    address: Optional[str] = None       # 住址 可选字段


@app.post('/users')
def add_user(user: User):
    return {'msg': f'recv user info ,name is {user.name}'}

pydantic 会根据你定义的User类,对POST请求里的json数据进行格式检查,包括字段的类型,是否可选,这需要你对python的类型标注有一定的掌握。

在add_user函数里,你可以通过attribute-style 的方式获取user的属性,想以字典的形式得到user对象的全部属性,可以使用user.json() 方法,它是pydantic对象转字典的方法。

通过测试代码对服务是否可用进行检查

import requests

data = {
    'name': 'lili',
    'age': 20,
    'address': '北京'
}
res = requests.post("http://127.0.0.1:8000/users", json=data)
print(res.text)

得到返回结果

{"msg":"recv user info ,name is lili"}

这说明POST请求发送的json数据被正确解析,且通过了schema验证。

2. 嵌套模型

在第一小节里所举的例子过于简单了,真实的项目开发中,提交的json数据往往都是很复杂的,是信息之间具有嵌套关系,比如下面的post请求

import requests

data = {
    'name': '小明',
    'age': 20,
    'address': '北京',
    'family': {
        'father': '小明爸爸',
        'mother': '小明妈妈'
    },
    'school':{
        'name': '育英中学',
        'address': '育英路'
    },
    'course': [{'name': '语文', 'score': 100}, {'name': '数学', 'score': 100}]

}
res = requests.post("http://127.0.0.1:8000/users", json=data)
print(res.json())

family 和 school 是嵌套的字典,course是一个列表,对于着这样的json数据,在服务端,你需要这样来定义schema

from typing import Optional,List
from pydantic import BaseModel
from fastapi import FastAPI

app = FastAPI()


class SchoolInfo(BaseModel):
    name: str      # 学校名称
    address: str   # 学校地址


class FamilyInfo(BaseModel):
    father: str    # 父亲姓名
    mother: str    # 母亲姓名

class Course(BaseModel):
    name: str       # 课程名称
    score: float    # 分数

class User(BaseModel):
    name: str       # 姓名
    age: int        # 年龄
    address: Optional[str] = None       # 住址 可选字段
    family: FamilyInfo      # 家庭信息
    school: SchoolInfo      # 学校信息
    course: List[Course]    # 课程信息


@app.post('/users')
def add_user(user: User):
    return user.json()

除了PSOT请求,PATCH,PUT请求同样可以携带请求体,对于他们可以使用相同的方法来处理。

3. 解析from表单

想要解析post请求提交的form表单,需要先安装python-multipart

pip install python-multipart

我们先编写一段测试代码

from urllib import parse
import requests

data = {
    'username': 'lili',
    'password': 'pd'
}

data = parse.urlencode(data)
headers = {"Content-Type":"application/x-www-form-urlencoded"}

res = requests.post("http://127.0.0.1:8000/login", data=data, headers=headers)
print(res.json())

想要发送form表单,需要指定Content-Type的类型是application/x-www-form-urlencoded, 对data进行url编码,转成字符串,其内容为

username=lili&password=pd

接下来,完成服务端的编写

from fastapi import FastAPI, Form

app = FastAPI()

@app.post('/login')
def login(username: str = Form(...), password: str = Form(...)):
    return {'username': username, 'password': password}

username和password参数必须在声明时显示的使用Form,这样才不会被解析成请求参数。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案