fastapi响应数据处理

密码使用场景

请求体和响应体的数据格式通常是不同的,如前端用户给后端服务器传递用户名、邮箱、手机号、密码等信息,后端给前端通常不会返回密码
EmailStr需要额外安装:pip install pydantic[email]
通过路径操作,path operation定义响应体的格式
请求体和响应体有关联的,可以通过定义共同的基类来节省代码

from typing import Optional, List
from pydantic import BaseModel, EmailStr

app04 = APIRouter()

"""Response Model 响应模型"""


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    mobile: str = "10086"
    address: str = None
    full_name: Optional[str] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr  # 用 EmailStr 需要 pip install pydantic[email]
    mobile: str = "10086"
    address: str = None
    full_name: Optional[str] = None


users = {
    "user01": {"username": "user01", "password": "123123", "email": "[email protected]"},
    "user02": {"username": "user02", "password": "123456", "email": "[email protected]", "mobile": "110"}
}


@app04.post("/response_model/", response_model=UserOut, response_model_exclude_unset=True)
async def response_model(user: UserIn):
    """response_model_exclude_unset=True表示默认值不包含在响应中,仅包含实际给的值,如果实际给的值与默认值相同也会包含在响应中"""
    print(user.password)  # password不会被返回
    # return user
    return users["user01"]


@app04.post(
    "/response_model/attributes",
    response_model=UserOut,
    # response_model=Union[UserIn, UserOut],    # 返回两者的并集字段
    # response_model=List[UserOut],      # 返回结果是多个包括userout类型的列表
    response_model_include=["username", "email", "mobile"],     # 需要在结果中包含的字段
    response_model_exclude=["mobile"]     # 需要排除的字段
)
async def response_model_attributes(user: UserIn):
    # del user.password  # Union[UserIn, UserOut]后,删除password属性也能返回成功
    return user
    # return [user, user]

表单数据处理

from fastapi import Form

@app04.post("/login/")
async def login(username: str = Form(...), password: str = Form(...)):  # 定义表单类型,...为必填
    """用Form类需要pip install python-multipart; Form类的元数据和校验方法类似Body/Query/Path/Cookie"""
    return {"username": username}

单文件,多文件上传

需要导入file和uploadfile,当使用file文件会用2进制形式写入内存,只适合小文件上传,文件太大会爆内存

@app04.post("/file")
# 如果要上传多个文件 files: List[bytes] = File(...)
async def file_(file: bytes = File(...)):
    return {"file_size": len(file)}

在docs中可以看到定义了file类型后,请求就变为了form-data,在vue端编写请求的时候,可以参考
fastapi响应数据处理_第1张图片
上传大文件需要使用uploadfile,使用UploadFile类的优势:

  1. 文件存储在内存中,使用的内存达到阈值后,将被保存在磁盘中
  2. 适合于图片、视频大文件
  3. 可以获取上传的文件的元数据,如文件名,创建时间等
  4. 有文件对象的异步接口,可以异步方式读取或更改文件
  5. 上传的文件是Python文件对象,可以使用write(), read(), seek(), close()操作
async def upload_files(files: List[UploadFile] = File(...)):
    for file in files:
        contents = await file.read()
        print(contents)
    return {"filename": files[0].filename, "content_type": files[0].content_type} # 返回第一个文件的数据

可以看到return输出的文件类型为application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
在用python或其它语言时,实现下载excel功能或者是上传,要使用content_type定义类型

@app.get("/File")
async def get_file():
	filepath = "./data/demo.xlsx"
	filename = "demo.xlsx"
	headers = {
		"Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
	}
	return FileResponse(filepath, filename=filename, headers=headers)

在终端看到的输出就是乱码
https://www.w3school.com.cn/media/media_mimeref.asp 可以看到其它常用格式的content_type

静态文件配置

静态文件也属于一种返回的形式,需要配置,在项目根路径新建static文件夹,之后在run.py即运行主文件中挂载,对于fastapi而言,static只是一个独立应用,与fastapi无关
app.mount(self,path,app,name) ,特别注意,只能挂在到FastAPI中不要挂到APIRouter中

from fastapi.staticfiles import StaticFiles
app.mount(path='/static', app=StaticFiles(directory='./static'), name='static')

路径操作配置

主要用于响应的描述,响应的数据格式,响应状态码等。
deprecated=True ,用于标注该接口已经废弃掉,但依然可以使用
tags=[‘’,‘’] ,接口的描述,可以添加多个,但是不建议,因为会很混乱

响应状态码

状态码可以在路径中的status_code中定义

from fastapi import status
@app04.post("/status_attribute", status_code=status.HTTP_200_OK)
async def status_attribute():
    print(type(status.HTTP_200_OK))    # int类型 
    return {"返回的内容": "返回200状态码"}

如上,推荐使用status,不建议直接返回数字,因为语义化更明确。执行之后在docs中可以看到相应的codefastapi响应数据处理_第2张图片

fastapi应用的配置

在主文件中的FastAPI可以配置应用,title标题,description简介,version版本号,docs_url接口测试地址(默认是/docs),redoc_url(不能操作,可以给用户参考用,默认/redocs)

错误处理(不常用)

通过 from fastapi import HTTPException 捕获错误
if判断,满足条件后,raise抛出raise HTTPException(status_code=404, detail="City not found!", headers={"X-Error": "Error"}),headers为在response headers中插入值
fastapi响应数据处理_第3张图片
想所有应用都用自定义的错误相应,就要在主文件run.py中配置

from fastapi.exceptions import RequestValidationError  # 请求错误校验处理
from fastapi.responses import PlainTextResponse   # 文本形式返回response
from fastapi import HTTPException
from starlette.exceptions import HTTPException as StarletteHTTPException  # fastapi建立在starlette基础之上,所以与上一项的导入相同

重写http异常处理,其中request必须有,exc是错误

@app.exception_handler(StarletteHTTPException)  # 重写HTTPException异常处理器,把原来的错误信息从json改为文本形式
async def http_exception_handler(request, exc):
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)

PlainTextResponse的作用是:返回一些纯文本数据
重写请求验证的错误处理

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
    return PlainTextResponse(str(exc), status_code=400)

新建路由,验证错误处理

@app04.get("/http_exception/{city_id}")
async def override_http_exception(city_id: int):
    if city_id == 1:
        raise HTTPException(status_code=418, detail="Nope! I don't like 1.")
    return {"city_id": city_id}

你可能感兴趣的:(fastapi,fastapi,python,开发语言)