zoukankan      html  css  js  c++  java
  • 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)
  • 相关阅读:
    C# listView载入图片以大图标方式显示
    判断序列是否对称
    非走不可的弯路
    张国荣的《我》
    函数:找出一句话中的第二个单词
    压缩与解压缩示例:游标编码(runlength encoding)
    前行
    书单
    一个数组中的元素头尾两端依次对调
    第一遍读书笔记
  • 原文地址:https://www.cnblogs.com/poloyy/p/15318146.html
Copyright © 2011-2022 走看看