0%

FastAPI使用模型类接收表单(Form)数据

FastAPI

FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 3.8+ 并基于标准的 Python 类型提示。

官方文档:FastAPI (tiangolo.com)
英文文档:FastAPI (tiangolo.com)

本文默认情况:

问题描述

简单来说,无法通过官方推荐的pydantic来实现用模型类表示来自表单(Form)的字段。

在官方的文档中推荐使用pydanticBaseModel作为请求体的模型类。请求体 - FastAPI (tiangolo.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# python 3.10+
# 这里python版本的主要区别是参数可选类型的表示不同, 低版本需要用typing下的Union:
# 如 description: Union[str, None] = None

# 文件名 main.py
from fastapi import FastAPI
from pydantic import BaseModel


class Student(BaseModel):
id: int
name: str


app = FastAPI()


@app.post("/student")
async def create_student(stu: Student):
return stu

此时这个请求体中的所有参数都必须来自Body。具体如下图:
image-20240427221540885

如果我们修改Student模型类,增加一个字段,希望这个字段来自Query(即url),会发现不起作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from fastapi import FastAPI
from pydantic import BaseModel


class Student(BaseModel):
id: int
name: str
some_info: str = Query()


app = FastAPI()


@app.post("/student")
async def create_student(stu: Student):
return stu

image-20240427221752653

同理,你也无法通过以下方式表示Student模型类需要来自Form。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from fastapi import FastAPI
from pydantic import BaseModel


class Student(BaseModel):
id: int
name: str


app = FastAPI()


@app.post("/student")
async def create_student(stu: Student = Form()):
return stu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from fastapi import FastAPI
from pydantic import BaseModel


class Student(BaseModel):
id: int = Form()
name: str = Form()


app = FastAPI()


@app.post("/student")
async def create_student(stu: Student = Form()):
return stu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from fastapi import FastAPI, Depends
from pydantic import BaseModel


class Student(BaseModel):
id: int = Form()
name: str = Form()


app = FastAPI()


@app.post("/student")
async def create_student(stu: Student = Depends()):
return stu

解决方法

法1:参照官方文档,不使用模型类

将每个参数单独写在控制器入参中。

表单数据 - FastAPI (tiangolo.com)

Form Data - FastAPI (tiangolo.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from fastapi import FastAPI, Depends
from pydantic import BaseModel


# class Student(BaseModel):
# id: int = Form()
# name: str = Form()


app = FastAPI()


# @app.post("/student")
# async def create_student(stu: Student = Depends()):
# return stu
@app.post("/student")
async def create_student(id: int = Form(), name: str = Form()):
return {"id": id, "str": name}

法2:用dataclasses

使用数据类 - FastAPI (tiangolo.com)

dataclasses下的dataclass可以代替pydantic,并且能够实现用模型类定义Form数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from fastapi import FastAPI, Depends
from dataclasses import dataclass

@dataclass
class Student:
id: int = Form()
name: str = Form()


app = FastAPI()


@app.post("/student")
async def create_student(stu: Student = Depends()):
return stu

不仅如此,通过在模型类的字段中定义为<变量>: <类型> = Query()来指定url中的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from fastapi import FastAPI, Depends
from dataclasses import dataclass

@dataclass
class Student:
id: int = Form()
name: str = Form()
query_info: str = Query()


app = FastAPI()


@app.post("/student")
async def create_student(stu: Student = Depends()):
return stu

image-20240427222858853

另外,关于代码中Depends()的使用,可以参考文档类作为依赖项 - FastAPI (tiangolo.com) - 快捷方式。在这里一定要加上空的= Depends()

类作为依赖项 - FastAPI (tiangolo.com)

[Classes as Dependencies - FastAPI (tiangolo.com)](https://fastapi.tiangolo.com/tutorial/dependencies/classes-as-dependencies/?h= class depe#shortcut)


参考资料

python - How to use a Pydantic model with Form data in FastAPI? - Stack Overflow

FastAPI (tiangolo.com)