FastApi教程|额外型号

发表时间:2020-03-09

继续前面的示例,通常会有多个相关模型。

用户模型尤其如此,因为:

  • 输入模型 需要能够有一个密码。
  • 输出模式 不应该有一个密码。
  • 数据库模型 很可能需要有一个哈希密码。

危险

切勿存储用户的明文密码。 始终存储“安全哈希”,然后可以进行验证。

如果您不知道,您将在 安全性章节中 了解什么是“密码哈希” 。

多种型号

这是关于模型的密码字段和使用位置的大致概念:

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str = None


class UserInDB(BaseModel):
    username: str
    hashed_password: str
    email: EmailStr
    full_name: str = 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

关于 **user_in.dict()

Pydantic的 .dict()

user_in 是班级的金字塔模型 UserIn

Pydantic模型具有一种 .dict() 返回 dict 带有模型数据的方法。

因此,如果我们创建一个Pydantic对象, user_in 例如:

user_in = UserIn(username="john", password="secret", email="john.doe@example.com")

然后我们调用:

user_dict = user_in.dict()

现在,我们 dict 在变量中 有了一个 数据 user_dict (它是一个, dict 而不是Pydantic模型对象)。

如果我们打电话给:

print(user_dict)

我们将获得带有以下内容的Python dict

{
    'username': 'john',
    'password': 'secret',
    'email': 'john.doe@example.com',
    'full_name': None,
}

展开一个 dict

如果我们使用 dict like user_dict 将其传递给函数(或类) **user_dict ,Python将对其进行“解包”。 它将直接将键和 user_dict 键的值作为键值参数 传递 。

因此, user_dict 从上面 继续 ,编写:

UserInDB(**user_dict)

会导致以下结果:

UserInDB(
    username="john",
    password="secret",
    email="john.doe@example.com",
    full_name=None,
)

更确切地说, user_dict 直接 使用 其将来可能包含的任何内容:

UserInDB(
    username = user_dict["username"],
    password = user_dict["password"],
    email = user_dict["email"],
    full_name = user_dict["full_name"],
)

来自另一个内容的Pydantic模型

正如上面我们得到了例如 user_dict user_in.dict() ,此代码:

user_dict = user_in.dict()
UserInDB(**user_dict)

等同于:

UserInDB(**user_in.dict())

......因为 user_in.dict() 是一个 dict ,然后我们使Python“解包”,它通过它传递给 UserInDB 除了前面 **

因此,我们从另一个Pydantic模型中的数据中获得了Pydantic模型。

展开a dict 和额外的关键字

然后添加额外的关键字参数 hashed_password=hashed_password ,例如:

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

...最终像:

UserInDB(
    username = user_dict["username"],
    password = user_dict["password"],
    email = user_dict["email"],
    full_name = user_dict["full_name"],
    hashed_password = hashed_password,
)

警告

支持的附加功能仅仅是演示数据的可能流,但是它们当然并不能提供任何真正的安全性。

减少重复

减少代码重复是 FastAPI 的核心思想之一 。

随着代码重复的增加,错误,安全性问题,代码不同步问题(当您在一个地方进行更新而不是在另一个地方进行更新)等问题的机会也将增加。

这些模型都共享大量数据,并复制属性名称和类型。

我们可以做得更好。

我们可以声明一个 UserBase 模型作为其他模型的基础。 然后,我们可以使该模型的子类继承其属性(类型声明,验证等)。

所有数据转换,验证,文档编制等仍将正常运行。

这样,我们可以只声明模型之间的差异(使用明文 password ,使用 hashed_password 和不使用密码):

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserBase(BaseModel):
    username: str
    email: EmailStr
    full_name: str = None


class UserIn(UserBase):
    password: str


class UserOut(UserBase):
    pass


class UserInDB(UserBase):
    hashed_password: str


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

Union anyOf

您可以将响应声明 Union 为两种类型的,这意味着该响应将是两种类型中的任何一种。

它将在OpenAPI中使用进行定义 anyOf

为此,请使用标准的Python类型提示 typing.Union

from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class BaseItem(BaseModel):
    description: str
    type: str


class CarItem(BaseItem):
    type = "car"


class PlaneItem(BaseItem):
    type = "plane"
    size: int


items = {
    "item1": {"description": "All my friends drive a low rider", "type": "car"},
    "item2": {
        "description": "Music is my aeroplane, it's my aeroplane",
        "type": "plane",
        "size": 5,
    },
}


@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])
async def read_item(item_id: str):
    return items[item_id]

型号清单

同样,您可以声明对象列表的响应。

为此,请使用标准Python typing.List

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

任意响应 dict

您还可以使用简单的任意 dict 声明(仅声明键和值的类型)来 声明响应 ,而无需使用Pydantic模型。

如果您事先不知道有效的字段/属性名称(Pydantic模型需要此名称),这将很有用。

在这种情况下,您可以使用 typing.Dict

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}

回顾

使用多个Pydantic模型,并针对每种情况自由继承。

如果每个实体必须能够具有不同的“状态”,则不需要每个实体具有单个数据模型。 例如,用户“实体”的状态包括 password password_hash 没有密码。

文章来源互联网,如有侵权,请联系管理员删除。邮箱:417803890@qq.com / QQ:417803890

微配音

Python Free

邮箱:417803890@qq.com
QQ:417803890

皖ICP备19001818号-4
© 2019 copyright www.pythonf.cn - All rights reserved

微信扫一扫关注公众号:

联系方式

Python Free