响应模型
添加响应模型
from typing import Any
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: str | None = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: str | None = None
# 通过 response_model 设置返回模型
@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
return user
模型的其他操作
继承 & 解包
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI()
# 定义一个 Base
# 包含公共属性,比如 id create_time update_time 等
class UserBase(BaseModel):
username: str
email: EmailStr
full_name: str | None = None
# 继承 Base
class UserIn(UserBase):
password: str
# 继承 Base
class UserOut(UserBase):
pass
# 继承 Base
class UserInDB(UserBase):
hashed_password: str
def fake_password_hasher(raw_password: str):
return "supersecret" + raw_password
def fake_save_user(user_in: UserIn):
hashed_password = fake_password_hasher(user_in.password)
# 解包
# user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
# **user_in.dict() ==>
# username = user_dict["username"],
# password = user_dict["password"],
# email = user_dict["email"],
# full_name = user_dict["full_name"],
user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
print("User saved! ..not really")
return user_in_db
@app.post("/user/", response_model=UserOut)
async def create_user(user_in: UserIn):
user_saved = fake_save_user(user_in)
return user_saved
组合模型 (Union & dict)
union
union:组合多个模型,但返回值只能是一个模型的实例
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class BaseItem(BaseModel):
description: str
type: str
class CarItem(BaseItem):
type: str = "car"
class PlaneItem(BaseItem):
type: str = "plane"
size: int
items = {
"item1": {"description": "All my friends drive a low rider", "type": "car"},
"item2": {
"description": "Music is my aeroplane, it's my aeroplane",
"type": "plane",
"size": 5,
},
"item3": [
{
"description": "item3_1 Music is my aeroplane, it's my aeroplane",
"type": "plane",
"size": 5,
},
{
"description": "item3_2 Music is my aeroplane, it's my aeroplane",
"type": "plane",
"size": 5,
},
]
}
# Union[PlaneItem, CarItem, list[PlaneItem]],。。。。]
# 允许返回 Union 的多种类型中的 一种
@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem,list[PlaneItem]])
async def read_item(item_id: str):
return items[item_id]
dict
response_model=dict ,
response_model=dict[str, list] ,
response_model=list …dict 有点类似于 any, 但又比 any 更具体一些
比如 any 可以是 list 也可以是 dict, 但 dict 只能是 dict 不能是 list
比如 dict 可以是 dict[str, list], dict[int, list] 等,但 dict[str, list] 只能是 dict[str, list]
from fastapi import FastAPI
app = FastAPI()
# 测试 Any
@app.get("/test_any/")
async def read_keyword_weights():
# return {"foo": 2.3, "bar": 3.4}
return [1, 2, 3]
# 测试 dict
@app.get("/test_dict/", response_model=dict)
async def read_keyword_weights():
return {"foo": 2.3, "bar": [1, 2, 3]}
# 测试 dict[str, float]
@app.get("/test_dict_str_float/", response_model=dict[str, float])
async def read_keyword_weights():
return {"foo": 2.3, "bar": 3.4}
# return {"foo": 2.3, "bar": [1, 2, 3]}
响应状态码
from enum import IntEnum
from http import HTTPStatus
from fastapi import FastAPI, status
app = FastAPI()
# 通过 http模块的 HTTPStatus 类,
# 我们可以很方便的使用一些常见的状态码,如下
@app.get("/items/http_status", status_code=HTTPStatus.OK)
def test_status_code():
return "hallow world HTTPStatus"
# 通过 fastapi 的 status 模块,
# 我们可以很方便的使用一些常见的状态码,如下
@app.get("/items/status", status_code=status.HTTP_201_CREATED)
def test_status_code():
return "hallow world status"
# 也可以直接使用数字
@app.get("/items/num", status_code=201)
def test_status_code():
return "hallow world num"
顺便记一下,可以仿照 HTTPStatus 的写法,自定义状态码。
注意:自定义状态码是放到 响应体 里的,放到 status_code 后面有可能会报错哦
# 自定义的状态码
class MyHTTPStatus(IntEnum):
def __new__(cls, value, phrase, description=''):
obj = int.__new__(cls, value)
obj._value_ = value
obj.phrase = phrase
obj.description = description
return obj
Code200000 = 200000, 'OK', 'Request fulfilled, document follows'
# client error
Code400000 = (400000, 'Bad Request',
'Bad request syntax or unsupported method')
# 响应体示例
# {
# "code": 200000,
# "message": "OK",
# "data": {
# "name": "张三"
# }
# }
From表单
from fastapi import FastAPI, Form
app = FastAPI()
# 和 Boday Query 类似,Form 也是从 fastapi 导入
# username: str = Form()
@app.post("/login/")
async def login(username: str = Form(), password: str = Form()):
return {"username": username}
上传文件 (File, UploadFile)
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: bytes = File()):
return {"file_size": len(file)}
# 和前面的可选参数类似,如果 file 是可选的可以使用如下的方式声明
# file: UploadFile | None = None
# 多文件上传
# files: list[UploadFile]
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}
UploadFile 与 bytes 相比有更多优势:
- 使用 spooled 文件
- 存储在内存的文件超出最大上限时,FastAPI 会把文件存入磁盘
- 这种方式更适于处理图像、视频、二进制文件等大型文件,好处是不会占用所有内存
- 可获取上传文件的元数据
- 自带 file-like async 接口
- 暴露的 Python SpooledTemporaryFile 对象,可直接传递给其他预期「file-like」对象的库。
UploadFile
UploadFile 的属性
- filename:上传文件名字符串(str),例如, myimage.jpg;
- content_type:内容类型(MIME 类型 / 媒体类型)字符串(str),例如,image/jpeg;
- file: SpooledTemporaryFile( file-like 对象)。其实就是 Python文件,可直接传递给其他预期 file-like 对象的函数或支持库。
UploadFile 支持以下 async 方法
- write(data):把 data (str 或 bytes)写入文件;
- read(size):按指定数量的字节或字符(size (int))读取文件内容;
- seek(offset):移动至文件 offset (int)字节处的位置
- 例如,await myfile.seek(0) 移动到文件开头, 执行 await myfile.read() 后,需再次读取已读取内容时,这种方法特别好用;
- close():关闭文件
依赖项
声明依赖项
- 提高代码的复用性
from typing import Union
from fastapi import Depends, FastAPI
app = FastAPI()
# 为查询接口设置一些公共参数
async def common_parameters(
q: Union[str, None] = None, skip: int = 0, limit: int = 100
):
return {"q": q, "skip": skip, "limit": limit}
# 通过 Depends 声明依赖项
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
到此结 DragonFangQy 2024.07.13