码迷,mamicode.com
首页 > 其他好文 > 详细

响应模型

时间:2021-06-06 19:02:14      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:排除   密码   数据库   加密   return   过程   声明   none   内容   

一、基础

  响应模型与请求体模型类似,请求体就是通过Pydantic创建请求体模型,可用于对请求内容进行校验,响应模型就是对响应体进行校验。可以在任意的路径操作中使用response_model参数来声明响应的模型:

1、基本模型

from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


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


class UserOut(BaseModel):
    username: str
    email: EmailStr
    address: str = None
    full_name: Optional[str] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):
    return user

  上面定义了两个Pydantic模型,一个为请求体模型,另一个则是响应体模型。响应体模型在路径操作中进行声明,所以响应体数据会经过这个模型校验,返回的数据是符合这个模型的数据。显然响应体模型过滤掉了password字段。

2、response_model_exclude_unset

该参数的作用是表示默认值不包含在响应中,仅包含实际给的值,如果实际给的值与默认值相同也会包含在响应中。

...
@app.post("/user/", response_model=UserOut,response_model_exclude_unset=True)
async def create_user(user: UserIn):
    return user
...

此时如果发送的请求体内容是:

{
  "username": "zhangsan",
  "password": "123456",
  "email": "user@example.com"
}

显然address和full_name的字段值都是默认 的None,这样响应体不会返回这些默认值,实际响应内容为:

{
  "username": "zhangsan",
  "email": "user@example.com"
}

3、response_model_exclude

 顾名思义,该参数是排除响应模型中返回数据的字段:

...
@app.post("/user/", response_model=UserOut, response_model_exclude=["address"])
async def create_user(user: UserIn):
    return user
...

请求体:

{
  "username": "zhangsan",
  "password": "123456",
  "email": "user@example.com",
  "address": "张三村",
  "full_name": "张三"
}

响应体中已经排除了address字段:

{
  "username": "zhangsan",
  "email": "user@example.com",
  "full_name": "张三"
}

4、response_model_include

 该字段表示响应模型应该包含的字段:

...
@app.post("/user/", response_model=UserOut, response_model_include=["address"])
async def create_user(user: UserIn):
    return user
...

请求体:

{
  "username": "zhangsan",
  "password": "123456",
  "email": "user@example.com",
  "address": "张三村",
  "full_name": "张三"
}

响应体中只包含address字段:

{
  "address": "张三村"
}

注意:response_model_exclude和response_model_include的值本质是将列表转成了set,所以如果使用这样response_model_include={"address"}的格式完全没问题。

二、进阶

1、多模型配合

一个业务开发需要配合多个模型,比如创建一个新用户的操作:

from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


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


class UserOut(BaseModel):
    username: str
    email: EmailStr
    address: str = None
    full_name: Optional[str] = None


class UserInDB(BaseModel):
    username: str
    hashed_password: str
    email: EmailStr
    address: str = None
    fullname: Optional[str] = None


def fake_password_hasher(raw_password: str):
    return "secret" + raw_password


def fake_save_user(user_in: UserIn):
    hashed_password = fake_password_hasher(user_in.password)
    user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
    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

在这个过程中:

  • 接受客户端的用户请求体信息
  • 对请求体内容进行校验
  • 对请求体的密码进行hash加密
  • 对数据库用户模型进行校验
  • 获取符合数据库用户模型的数据,并且存入数据库
  • 向客户端返回这个已经创建的用户信息

 2、**user_in.dict()

 如果创建一个Pydantic模型,那么怎么创建一个模型对象呢?

...
user_in = UserIn(username="zhang san",
                     password="123456",
                     email="user@example.com",
                     address="zhang san street",
                     full_name="zhangsan")
...

  这样就创建了一个UserIn模型的对象,显然FastAPI中声明UserIn类型,这样会将请求体转为Pydantic定义的UserIn的模型对象,也就是实现了上述过程。那么通过user_in.dict()又做了什么呢?顾名思义就是将上述user_in对象转成key-value的字典格式,就是一个dict数据类型。

{
    username: zhangsan,
    password: 123456,
    email: user@example.com,
    address: zhangsanstreet,
    full_name: zhangsan
}

如果现在有这样一个字典类型的数据,如何传递给Pydantic的模型类,使其创建一个模型类对象,Python使用了字典(dict)解包的方式。所以对于:

UserInDB(**user_in.dict(), hashed_password=hashed_password)

通过**来对字典解包,形成的结果就是:

UserInDB(
    username=zhangsan,
    password=123456,
    email=user@example.com,
    address=zhangsanstreet,
    full_name=zhangsan,
    hashed_password=hashed_password
)

但是通过UserInDB模型类的校验后生成的最终结果就是:

UserInDB(
    username=zhangsan,
    hashed_password=hashed_password,
    email=user@example.com,
    address=zhangsanstreet,
    full_name=zhangsan
)

3、Union/List

  • Union
from typing import Optional, Union, List
...

@app.post("/response/model", response_model=Union[UserIn, UserOut])
async def response_model(user: UserIn):
    return user

...

Union的作用就是将Union中模型的字段取并集,显然,如果只是UserOut模型,结果是不会返回password字段,但是把UserIn模型也放入Union中,取两个模型并集后的字段作为响应模型进行校验响应的user数据。

  • List
...
@app.post("/response/model", response_model=List[UserOut])
async def response_model():
    user_list = [
        {
            username: zhangsan,
            password: 123456,
            email: user@example.com,
            address: zhangsanstreet,
            full_name: zhangsan
        },
        {
            username: lisi,
            password: 123456,
            email: user@example.com,
            address: lisistreet,
            full_name: lisi
        }
    ]
    return user_list
...

这样响应的内容是由对象构成的列表。其响应的内容:

[
  {
    "username": "zhangsan",
    "email": "user@example.com",
    "address": "zhangsanstreet",
    "full_name": "zhangsan"
  },
  {
    "username": "lisi",
    "email": "user@example.com",
    "address": "lisistreet",
    "full_name": "lisi"
  }
]

4、dict构成响应

 当不声明任何响应的Pydantic模型时,此时并不知道有效的字段,那么可以通过声明普通的键值对dict类型:

from typing import Dict
from fastapi import FastAPI

app = FastAPI()


@app.get("/apple/dict/", response_model=Dict[str, float])
async def apple_dict():
    return {"apple": 3.14, "pear": 5.12}

三、状态码

 响应状态码用于服务器返回给客户端响应的状态,常用的有:

  • 200及以上   成功的响应
  • 300及以上   重定向
  • 400及以上   客户端错误
  • 500及以上   服务端错误

FastAPI的路径操作中可以使用status_code参数来声明HTTP状态码。FastAPI中可以通过状态码数字、状态码变量方式来使用。

1、状态码数字

from fastapi import FastAPI

app = FastAPI()


@app.post("/status_code/", status_code=200)
async def status_code():
    return {"status_code": 200}

2、状态码变量

如果不记得具体的数字,此时可以使用提供的变量形式。

from fastapi import FastAPI, status

app = FastAPI()


@app.post("/status_attribute/", status_code=status.HTTP_200_OK)
async def status_code():
    return {"status_code": status.HTTP_200_OK}

这与上面的数字效果是一样的。两种方式都可以,其表现形式如下:

技术图片

 

响应模型

标签:排除   密码   数据库   加密   return   过程   声明   none   内容   

原文地址:https://www.cnblogs.com/shenjianping/p/14852051.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!