响应模型与请求体模型类似,请求体就是通过Pydantic创建请求体模型,可用于对请求内容进行校验,响应模型就是对响应体进行校验。可以在任意的路径操作中使用response_model参数来声明响应的模型:
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字段。
该参数的作用是表示默认值不包含在响应中,仅包含实际给的值,如果实际给的值与默认值相同也会包含在响应中。
... @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" }
顾名思义,该参数是排除响应模型中返回数据的字段:
... @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": "张三" }
该字段表示响应模型应该包含的字段:
... @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"}的格式完全没问题。
一个业务开发需要配合多个模型,比如创建一个新用户的操作:
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
在这个过程中:
如果创建一个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‘ )
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数据。
... @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" } ]
当不声明任何响应的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}
响应状态码用于服务器返回给客户端响应的状态,常用的有:
FastAPI的路径操作中可以使用status_code参数来声明HTTP状态码。FastAPI中可以通过状态码数字、状态码变量方式来使用。
from fastapi import FastAPI app = FastAPI() @app.post("/status_code/", status_code=200) async def status_code(): return {"status_code": 200}
如果不记得具体的数字,此时可以使用提供的变量形式。
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}
这与上面的数字效果是一样的。两种方式都可以,其表现形式如下:
原文:https://www.cnblogs.com/shenjianping/p/14852051.html