FastAPI from entry to actual combat (10) - response model and status code

What has been recorded before is the request-related content. This article starts to record the response-related content, including request model and model inheritance, status code and other related content.

An arbitrary dict of basic responses

# 任意dict构成的响应
@app06.get("/stu06/dict", response_model=Dict[str, float])
async def stu06_read_keyword_weights():
    return {
    
    "foo": 2.3, "bar": 3.4}

The above is a response model that uses Dictdeclarations. You only need to declare the types of keys and values ​​to respond directly.

image-20221129181122307

Define the base response model

# 定义一个基本模型类
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

Here, Pydantica basic model class is defined, including username、passwordfields such as , and then a postrequest is declared, and the default Querytype of the request parameter is used. After the server receives the request, the received data userInwill be returned in the type of .

image-20221129224540214

Define output response model

# 添加一个输出模型类
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

The above example does not reflect the role of the response model class. In order to show it more clearly, a class is redefined here. The name of the class is called. Compared userOutwith the above example, there is one less passwordparameter, and then it is also a postrequest, and the server accepts A userInparameter of a type, and then return the received data as userOuta type, and the response result has no passwordfields.

image-20221129224655033

set values ​​for the model

userItem = {
    
    
    "name1": {
    
    "username": "name1", "password": "12312312", "email": "[email protected]"},
    "name2": {
    
    "username": "name2", "password": "12312312", "email": "[email protected]", "sex": "girl", "age": 25},
    "MinChess": {
    
    "username": "MinChess", "password": "12312312", "email": "[email protected]", "sex": None,
                 "age": 22}
}


# 响应详细参数
@app06.get("/stu06/response_item", response_model=userOut)
def stu06_response_item(
        username: str = Query(...)
):
    return userItem[username]

Usually in web development, the response data is requested from the database. For example, when a user logs in, only the user name and password will be sent when the request is made. When returning, it needs to return more basic information filled in by the previous user registration, such as name , gender, age, etc.;

Here we first define a dictionary , the value of the userItemdictionary is a dictionary; then define a request, the request parameter is ; the front end sends a request with , after the server receives the request, it matches in it, and after matching the corresponding field Return as type.keyusernamevaluegetusernameusernameuserItemuserOut

image-20221129224833928

Response Field Control

Ignore unset parameter 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]

As in the previous example, when usernamefor name1, the returned field is userOutall the fields in the field, but there is no field name1in the named dictionary ; in this case, you can control it by setting parameters;age、sexresponse_model_exclude_nset=True

image-20221129224849330

Response ignore defaults 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]

Similarly, when we get the data and find that it is the same as the default data, we need to ignore it automatically, which can be response_model_exclude_defaults=Trueachieved by setting parameters, that is, we find uesrItemthat the default value of the field named name2in the dictionary is the same as the default value of the sexdefined response model class userOut, we ignore it;

Of course, the actual situation will definitely not be the default gender...

image-20221129224905361

Response ignore None field 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]

In the same way, when we need to ignore empty fields, we can response_model_exclude_none=Truedo so by setting parameters. The actual application is that in the database, if some fields are empty, it will affect the user experience, so we can directly filter the empty fields by setting this way;

The above example is, MinChessin the field named, sex字段为None, then we will not return.

image-20221129224930523

The response only contains the specified field 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]

The model class we defined may not be suitable for all scenarios. Some pages only need avatar or name, but it is completely unnecessary to redefine a class when there are many parameters, so it can be specified manually, such as the above example, specified response_model_include=["username","age"]return usernameand agefields.

image-20221129224945565

The response excludes the specified field 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]

After figuring out the above, this is very easy, just ignore some fields, here is to ignore emailthe fields.

image-20221129225006030

model list

# 模型列表
@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]]

The model list means that the content of the response is a list. The list is a certain model category we defined, such as the management system, which returns a lot of data of the same type, but the actual application is definitely not as usernamemuch

Just set it directly here response_model, List类型where List is userOuta class;

image-20221129225036700

model inheritance

# 基本类
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

In fact, this part does not mainly record the content related to the response, but mainly records an idea. In practical applications, for the same user table, the fields involved in login, response, and storage are all different, so you can define basic classes , and then inherit to implement the extension. This reduces a lot of repetitive code;

For some specific knowledge points and operations, please refer to the above notes, which are very clear!

image-20221129225408766

Status code setting

HTTP status code

The HTTP status code consists of three decimal numbers. The first decimal number defines the type of the status code, and the last two numbers have a classification function. Different status codes represent different meanings.

Classification of HTTP status codes

There are 5 types:

Classification Category description
1xx Information, the server receives the request and needs the requester to continue to perform the operation
2xx Success, the operation was successfully received and processed
3xx Redirected, further action is required to complete the request
4xx Client error, the request contained a syntax error or could not be completed
5xx Server error, the server encountered an error while processing the request

Common Status Codes & Meanings

200 - 请求成功,已经正常处理完毕

301 - 请求永久重定向,转移到其它URL

302 - 请求临时重定向

304 - 请求被重定向到客户端本地缓存

400 - 客户端请求存在语法错误

401 - 客户端请求没有经过授权

403 - 客户端的请求被服务器拒绝,一般为客户端没有访问权限

404 - 客户端请求的URL在服务端不存在

500 - 服务端永久错误

direct use of digital claims

@app06.get("/stu06/statuscode",status_code=200)
async def stu06_status():
    return {
    
    "status-code":200}

The above code defines the response status code as 200 directly in the request statement;

image-20221129180157668

Setup with FastAPI

@app06.get("/stu06/statuscode_fastapi",status_code=status.HTTP_200_OK)
def stu06_fastcode():
    return {
    
    "status-code":200}

Here is fastapi.statusthe convenience variable that is set using

image-20221129180401422

source code

# -*- 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": "[email protected]"},
    "name2": {
    
    "username": "name2", "password": "12312312", "email": "[email protected]", "sex": "girl", "age": 25},
    "MinChess": {
    
    "username": "MinChess", "password": "12312312", "email": "[email protected]", "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}

Thanks for reading!

Blog link: FastAPI from entry to actual combat (10) - response model and status code

Guess you like

Origin blog.csdn.net/qq_45730223/article/details/128107079