FastAPI(21)- 多个模型的代码演进

前言

在一个完整的应用程序中,通常会有很多个相关模型,比如

  • 请求模型需要有 password
  • 响应模型不应该有 password
  • 数据库模型可能需要一个 hash 加密过的 password

 

多个模型的栗子

需求

  • 注册功能
  • 请求输入密码
  • 响应不需要输出密码
  • 数据库存储加密后的密码

 

实际代码

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠萝测试笔记
# blog:  https://www.cnblogs.com/poloyy/
# time: 2021/9/22 8:28 上午
# file: 19_extra models.py
"""

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

app = FastAPI()


# 请求模型
class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Optional[str] = None


# 响应模型
class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None


# 数据库模型
class UserInDB(BaseModel):
    username: str
    hashed_password: str
    email: EmailStr
    full_name: Optional[str] = None


# 加密算法
def fake_password_hasher(password: str) -> str:
    return "supersecret" + password


# 数据库存储
def fake_save_user(user: UserIn):
    # 取出用户的密码进行加密
    hash_password = fake_password_hasher(user.password)
    # 转换为数据库模型
    userInDB = UserInDB(**user.dict(), hashed_password=hash_password)
    # 返回数据
    return userInDB


@app.post("/user", response_model=UserOut)
async def create_user(user: UserIn):
    # 创建用户,落库
    user_saved = fake_save_user(user)
    # 返回存储后的用户信息
    return user_saved

if __name__ == "__main__":
    uvicorn.run(app="19_extra_models:app", host="127.0.0.1", port=8080, reload=True, debug=True)

 

.dict()

是 Pydantic 提供的方法,将模型的实例对象转换为 dict 

Pydantic 入门篇

 

**user.dict()

先将 user 转成 dict,然后解包

Python 解包教程

 

减少代码重复

核心思想

  • 减少代码重复是 FastAPI 的核心思想之一。
  • 因为代码重复增加了错误、安全问题、代码同步问题(当在一个地方更新而不是在其他地方更新时)等的可能性

 

上面代码存在的问题

三个模型都共享大量数据

 

利用 Python 继承的思想进行改造

  • 声明一个 UserBase 模型,作为其他模型的基础
  • 然后创建该模型的子类来继承其属性(类型声明、验证等),所有数据转换、验证、文档等仍然能正常使用
  • 这样,不同模型之间的差异(使用明文密码、使用哈希密码、不使用密码)也很容易识别出来
#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠萝测试笔记
# blog:  https://www.cnblogs.com/poloyy/
# time: 2021/9/22 8:28 上午
# file: 19_extra models.py
"""

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

app = FastAPI()


# 基类模型
class UserBase(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None


# 请求模型
class UserIn(UserBase):
    password: str


# 响应模型
class UserOut(UserBase):
    pass


# 数据库模型
class UserInDB(UserBase):
    hashed_password: str


# 加密算法
def fake_password_hasher(password: str) -> str:
    return "supersecret" + password


# 数据库存储
def fake_save_user(user: UserIn):
    # 取出用户的密码进行加密
    hash_password = fake_password_hasher(user.password)
    # 转换为数据库模型
    userInDB = UserInDB(**user.dict(), hashed_password=hash_password)
    # 返回数据
    return userInDB


@app.post("/user", response_model=UserOut)
async def create_user(user: UserIn):
    # 创建用户,落库
    user_saved = fake_save_user(user)
    # 返回存储后的用户信息
    return user_saved


if __name__ == "__main__":
    uvicorn.run(app="19_extra models:app", host="127.0.0.1", port=8080, reload=True, debug=True)

 

posted @ 2021-09-25 10:08  小菠萝测试笔记  阅读(418)  评论(0编辑  收藏  举报