FastAPI从入门到实战(10)——响应模型与状态码
前面一直记录的是请求相关的内容,这篇文章开始记录一下响应相关的内容,包括请求模型和模型继承以及状态码等相关的内容。
一个任意dict构成的基本响应
# 任意dict构成的响应
@app06.get("/stu06/dict", response_model=Dict[str, float])
async def stu06_read_keyword_weights():
return {"foo": 2.3, "bar": 3.4}
上面是用
Dict
声明的一个响应模型,只需要声明键和值的类型,就能直接响应。
定义基本响应模型
# 定义一个基本模型类
class userIn(BaseModel):
username: str
password: str
email: EmailStr
sex: str
age: int
# 响应模型:输出与输入相同的模型数据
@app06.post("/stu06/user_response", response_model=userIn)
def stu06_creat_user(user: userIn):
return user
这里利用
Pydantic
定义一个基本的模型类,包含username、password
等字段,然后声明一个post
请求,请求参数默认Query
类型,服务器接受到请求后将接收的数据再次以userIn
的类型进行返回。
定义输出响应模型
# 添加一个输出模型类
class userOut(BaseModel):
username: str
email: EmailStr
sex: Optional[str] = "girl"
age: Optional[int] = None
# 响应输出模型
@app06.post("/stu06/userout", response_model=userOut)
def stu06_response_userout(user: userIn):
return user
上面的例子不太能反映响应模型类的作用,为了更清楚的展示,这里重新定义一个类,类的名称叫做
userOut
,相较于上面的例子,少了一个password
参数,然后同样是一个post
请求,服务器接受一个userIn
类型的参数,然后将接收的数据以userOut
类型进行返回,响应结果就没有了password
字段。
为模型设置值
userItem = {
"name1": {"username": "name1", "password": "12312312", "email": "hidbiuwu@nenu.edu.cn"},
"name2": {"username": "name2", "password": "12312312", "email": "hidddwu@163.com", "sex": "girl", "age": 25},
"MinChess": {"username": "MinChess", "password": "12312312", "email": "MinChess@jiumoz.com", "sex": None,
"age": 22}
}
# 响应详细参数
@app06.get("/stu06/response_item", response_model=userOut)
def stu06_response_item(
username: str = Query(...)
):
return userItem[username]
通常web开发中,响应的数据都是从数据库进行请求的,比如说用户登录,请求的时候只会发送用户名和密码,返回就需要返回之前用户注册的时候填的更多的基本信息,例如姓名、性别、年龄等;
这里我们首先定义一个字典
userItem
,字典的key
为username
的值,value
为一个字典;然后定义一个get
请求,请求参数为username
;前端发送一个带有username
的请求,服务器接收请求后,在userItem
中进行匹配,匹配到对应的字段后以userOut
类型的形式进行返回。
响应字段控制
忽略未设置的参数 response_model_exclude_nset
# 响应未经参数设置的参数 response_model_exclude_nset=True
@app06.get("/stu06/response_exclude_unset", response_model=userOut, response_model_exclude_unset=True)
def stu06_response_item_exclude_unset(
username: str = Query("name1")
):
return userItem[username]
如上一个例子,当
username
为name1
的时候,返回是字段是userOut
内所有的字段,但是名为name1
的字典内,并没有age、sex
的字段;遇到这种情况,就可以通过设置参数response_model_exclude_nset=True
来进行控制;
响应忽略默认值response_model_exclude_defaults
# 响应忽略和默认值一样的字段 response_model_exclude_defaults=True
@app06.get("/stu06/response_exclude_defaults", response_model=userOut, response_model_exclude_defaults=True)
def stu06_response_item_exclude_defaults(
username: str = Query("name2")
):
return userItem[username]
同样,我们拿到数据发现和默认数据是相同的时候,需要自动忽略,就可以通过设置参数
response_model_exclude_defaults=True
来实现,即我们发现uesrItem
内,名为name2
的字典内sex
字段和定义的userOut
响应模型类的默认值是一样的,我们就进行忽略;当然实际情况肯定不会是默认一个性别吭…
响应忽略None字段response_model_exclude_none
# 响应忽略None字段 response_model_exclude_none=True
@app06.get("/stu06/response_exclude_none", response_model=userOut, response_model_exclude_none=True)
def stu06_response_item_exclude_none(
username: str = Query("MinChess")
):
return userItem[username]
同理,我们需要忽略空字段的时候,就可以通过设置
response_model_exclude_none=True
参数来实现了,实际应用就是数据库中,某些字段为空会影响用户的体验,那么就可以直接这样设置来过滤空字段;上面的例子就是,名为
MinChess
的字段内,sex字段为None
,那么我们就不进行返回。
响应只包含指定字段 response_model_include
# 响应只包含指定字段 response_model_include
@app06.get("/stu06/response_model_include", response_model=userOut, response_model_include=["username","age"])
def stu06_response_model_include(
username:str = Query("MinChess")
):
return userItem[username]
我们定义的模型类可能不适用于所有场景,有些页面只需要头像或者姓名,但是重新定义一个类在参数很多的情况下就完全没必要,所以就可以手动进行指定,如上面的例子
response_model_include=["username","age"]
,指定返回username
和age
字段。
响应排除指定字段 response_model_exclude
# 响应排除指定字段 response_model_exclude
@app06.get("/stu06/response_model_exclude", response_model=userOut,response_model_exclude=["email"])
def stu06_response_model_exclude(
username:str = Query("MinChess")
):
return userItem[username]
弄清楚了上面那个,这个就很容易了,就是忽略某些字段嘛,这里就是忽略
模型列表
# 模型列表
@app06.get("/stu06/response_users",response_model=List[userOut], response_model_exclude_none=True)
def sru06_response_users(
username1: Optional[str] = Query("name1"),
username2: Optional[str] = Query("name2")
):
return [userItem[username1],userItem[username2]]
模型列表就是响应的内容是一个列表,列表是我们定义的某个模型类类别的,比如管理系统,返回的就是很多个相同类的数据,但是实际应用肯定不是像这里这样传这么多
username
哈!这里就直接设置
response_model
为List类型
的就行,其中List为userOut
类的;
模型继承
# 基本类
class loginbase(BaseModel):
phone_number:str
name:str
# 登录时用到的类,在此基础上,需要增加密码和验证码的字段
class login(loginbase):
password:str
code:str
# 登录成功后返回给前端的类,返回的字段和基本类相同,不需要增加或删除,直接pass
class loginsuccess(loginbase):
pass
# 存储至数据库时的类,在基本模型基础上要添加一个经过处理的密码
class logindb(loginbase):
hash_password:str
# 伪密码处理函数
def password_hash(password:str):
return "hash——"+password
# 伪入库类:接收前端传来的login类
def login_database(loginparam:login):
# 将接收到的login类型下loginparam中的password字段进行处理(加密)
hashpassword = password_hash(loginparam.password)
# 首先通过Pydantic模型的.dict()方法将loginparam处理为拥有模型数据的dict
# 再通过**将其中的参数传递到logindb中,python对其进行解包,便能一一对应进行直接传递了
# 同时对hash_password进行另外关键字参数的设置
login_db = logindb(**loginparam.dict(),hash_password=hashpassword)
print("入库成功!",login_db.dict())
# 返回logindb类型的数据
return login_db
@app06.post("/stu06/login",response_model=loginsuccess)
async def stu06_login(login_param:login):
# 返回请求成功的类型的数据
loginsuc = login_database(login_param)
return loginsuc
这个部分其实不主要记录关于响应相关的内容,主要是记录一种思想,实际应用中就是对于同一个user表,登录、响应、存储所涉及的字段都是不同的,所以可以通过定义基本的类,然后进行继承来实现扩展。这样可以减少大量的重复代码;
具体的一些知识点和操作参看上面的注释,写的很明白!
状态码设置
HTTP状态码
HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字有分类的作用。不同的状态码代表不同的含义。
HTTP状态码分类
共分为5种类型:
分类 | 分类描述 |
---|---|
1xx | 信息,服务器收到请求,需要请求者继续执行操作 |
2xx | 成功,操作被成功接收并处理 |
3xx | 重定向,需要进一步的操作以完成请求 |
4xx | 客户端错误,请求包含语法错误或无法完成请求 |
5xx | 服务器错误,服务器在处理请求的过程中发生了错误 |
常见状态码&含义
200 - 请求成功,已经正常处理完毕
301 - 请求永久重定向,转移到其它URL
302 - 请求临时重定向
304 - 请求被重定向到客户端本地缓存
400 - 客户端请求存在语法错误
401 - 客户端请求没有经过授权
403 - 客户端的请求被服务器拒绝,一般为客户端没有访问权限
404 - 客户端请求的URL在服务端不存在
500 - 服务端永久错误
直接利用数字声明
@app06.get("/stu06/statuscode",status_code=200)
async def stu06_status():
return {"status-code":200}
上面的代码,就是直接在请求声明中定义了响应状态码为200;
利用FastAPI进行设置
@app06.get("/stu06/statuscode_fastapi",status_code=status.HTTP_200_OK)
def stu06_fastcode():
return {"status-code":200}
这里就是利用
fastapi.status
进行设置的便捷变量
源码
# -*- coding: utf-8 -*-
# @Time: 2022/11/29 11:17
# @Author: MinChess
# @File: stu06.py
# @Software: PyCharm
from fastapi import APIRouter, Query ,status
from pydantic import BaseModel, EmailStr, Field
from typing import Optional,List,Dict
app06 = APIRouter()
# 任意dict构成的响应
@app06.get("/stu06/dict", response_model=Dict[str, float])
async def stu06_read_keyword_weights():
return {"foo": 2.3, "bar": 3.4}
# 定义一个基本模型类
class userIn(BaseModel):
username: str
password: str
email: EmailStr
sex: str
age: int
# 响应模型:输出与输入相同的模型数据
@app06.post("/stu06/user_response", response_model=userIn)
def stu06_creat_user(user: userIn):
return user
# 添加一个输出模型类
class userOut(BaseModel):
username: str
email: EmailStr
sex: Optional[str] = "girl"
age: Optional[int] = None
# 响应输出模型
@app06.post("/stu06/userout", response_model=userOut)
def stu06_response_userout(user: userIn):
return user
userItem = {
"name1": {"username": "name1", "password": "12312312", "email": "hidbiuwu@nenu.edu.cn"},
"name2": {"username": "name2", "password": "12312312", "email": "hidddwu@163.com", "sex": "girl", "age": 25},
"MinChess": {"username": "MinChess", "password": "12312312", "email": "MinChess@jiumoz.com", "sex": None,
"age": 22}
}
# 响应详细参数
@app06.get("/stu06/response_item", response_model=userOut)
def stu06_response_item(
username: str = Query(...)
):
return userItem[username]
# 响应未经参数设置的参数 response_model_exclude_nset=True
@app06.get("/stu06/response_exclude_unset", response_model=userOut, response_model_exclude_unset=True)
def stu06_response_item_exclude_unset(
username: str = Query("name1")
):
return userItem[username]
# 响应忽略和默认值一样的字段 response_model_exclude_defaults=True
@app06.get("/stu06/response_exclude_defaults", response_model=userOut, response_model_exclude_defaults=True)
def stu06_response_item_exclude_defaults(
username: str = Query("name2")
):
return userItem[username]
# 响应忽略None字段 response_model_exclude_none=True
@app06.get("/stu06/response_exclude_none", response_model=userOut, response_model_exclude_none=True)
def stu06_response_item_exclude_none(
username: str = Query("MinChess")
):
return userItem[username]
# 响应只包含指定字段 response_model_include
@app06.get("/stu06/response_model_include", response_model=userOut, response_model_include=["username","age"])
def stu06_response_model_include(
username:str = Query("MinChess")
):
return userItem[username]
# 响应排除指定字段 response_model_exclude
@app06.get("/stu06/response_model_exclude", response_model=userOut,response_model_exclude=["email"])
def stu06_response_model_exclude(
username:str = Query("MinChess")
):
return userItem[username]
# 模型列表
@app06.get("/stu06/response_users",response_model=List[userOut], response_model_exclude_none=True)
def sru06_response_users(
username1: Optional[str] = Query("name1"),
username2: Optional[str] = Query("name2")
):
return [userItem[username1],userItem[username2]]
# 基本类
class loginbase(BaseModel):
phone_number:str
name:str
# 登录时用到的类,在此基础上,需要增加密码和验证码的字段
class login(loginbase):
password:str
code:str
# 登录成功后返回给前端的类,返回的字段和基本类相同,不需要增加或删除,直接pass
class loginsuccess(loginbase):
pass
# 存储至数据库时的类,在基本模型基础上要添加一个经过处理的密码
class logindb(loginbase):
hash_password:str
# 伪密码处理函数
def password_hash(password:str):
return "hash——"+password
# 伪入库类:接收前端传来的login类
def login_database(loginparam:login):
# 将接收到的login类型下loginparam中的password字段进行处理(加密)
hashpassword = password_hash(loginparam.password)
# 首先通过Pydantic模型的.dict()方法将loginparam处理为拥有模型数据的dict
# 再通过**将其中的参数传递到logindb中,python对其进行解包,便能一一对应进行直接传递了
# 同时对hash_password进行另外关键字参数的设置
login_db = logindb(**loginparam.dict(),hash_password=hashpassword)
print("入库成功!",login_db.dict())
# 返回logindb类型的数据
return login_db
@app06.post("/stu06/login",response_model=loginsuccess)
async def stu06_login(login_param:login):
# 返回请求成功的类型的数据
loginsuc = login_database(login_param)
return loginsuc
# 直接修改
@app06.get("/stu06/statuscode",status_code=200)
async def stu06_status():
return {"status-code":200}
# 通过fastapi设置
@app06.get("/stu06/statuscode_fastapi",status_code=status.HTTP_200_OK)
def stu06_fastcode():
return {"status-code":200}
感谢阅读!
博客链接:FastAPI从入门到实战(10)——响应模型与状态码
- 感谢你赐予我前进的力量