持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情
多模型
- 一个接口很多时候都会涉及多个模型,比如用户注册接口一般会有至少三个模型类:
UserIn、UserOut和UserDb - 之所以需要这三个模型类是因为:响应用户信息时不应该有密码,密码存DB时也不应该存明文的密码。
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: str
full_name: Union[str, None] = None
class UserOut(BaseModel):
username: str
email: str
full_name: Union[str, None] = None
class UserInDB(BaseModel):
username: str
hashed_password: str
email: str
full_name: Union[str, None] = None
def fake_password_hasher(raw_password: str):
return "supersecret" + 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)
print("User saved! ..not really")
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
- 这个例子中模拟了用户注册接口,接口返回的数据的类型是:
UserInDB,但是可以看到使用了response_model=UserOut,这样的话,响应给客户端数据时就会把密码这个字段过滤掉。
Pydantic的.dict()
- 上面的例子中也可以看到,在创建用户类:
UserDb时使用了user_in.dict() - 这个dict()是Pydantic类及子类实例化对象的自已绑定方法,用来将对象转化为一个字典。
UserInDB(**user_in.dict())
# 上面一行代码等价于下面具体实例化,因为user_in.dict() => 一个字典,
# 然后 **放在一个字典前面就相当于字典中的每个键值对给UserDb当关键字参数了
UserInDB(
username="john",
password="secret",
email="john.doe@example.com",
full_name=None,
)
简化模型类
- 上面用户注册接口使用了三个模型类,但是有多个字段重复定义了,我们可以简化它。
- 通过python中类的继承关系很容易实现。
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class UserBase(BaseModel):
username: str
email: str
full_name: Union[str, None] = None
class UserIn(UserBase):
password: str
class UserOut(UserBase):
pass
class UserInDB(UserBase):
hashed_password: str
响应模型是一个列表
- 响应模型可以是一个列表,列表中的每个元素都是Pydantic类型的对象
- 这种一般用在返回相同类型的全部数据,比如所有的商品信息等等。
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str
items = [
{"name": "Foo", "description": "There comes my hero"},
{"name": "Red", "description": "It's my aeroplane"},
]
@app.get("/items/", response_model=List[Item])
async def read_items():
return items
响应模型是普通字典
- 响应模型可以是普通的包含任意字段的字典
from typing import Dict
from fastapi import FastAPI
app = FastAPI()
@app.get("/keyword-weights/", response_model=Dict[str, float])
async def read_keyword_weights():
return {"foo": 2.3, "bar": 3.4}