zoukankan      html  css  js  c++  java
  • FastAPI(30)- Classes as Dependencies 类依赖注入

    依赖项函数返回 dict

    上一篇依赖注入文章中讲的依赖项函数返回值类型是 dict

    #!usr/bin/env python
    # -*- coding:utf-8 _*-
    """
    # author: 小菠萝测试笔记
    # blog:  https://www.cnblogs.com/poloyy/
    # time: 2021/9/24 1:08 下午
    # file: 25_dependency.py
    """
    from typing import Optional, Dict, Any
    # 2、导入 Depends
    from fastapi import Depends, FastAPI
    
    import uvicorn
    
    app = FastAPI()
    
    
    # 1、编写依赖项
    async def common_parameters(q: Optional[str] = None,
                                skip: int = 0,
                                limit: int = 100):
      # 返回 dict
        return {"q": q, "skip": skip, "limit": limit}
    
    
    # 3、编写路径操作函数,参数声明为 Depends
    @app.get("/items")
    async def read_items(commons: dict = Depends(common_parameters)):
        return commons
    
    
    if __name__ == "__main__":
        uvicorn.run(app="25_dependency:app", host="127.0.0.1", port=8080, reload=True, debug=True)

    依赖项函数返回一个 dict,然后路径操作函数的参数 commons 得到一个 dict,但 IDE 并不支持更多的代码智能提示,因为无法知道键、值的类型

    灵魂提问:怎么才算一个依赖项?

    • 上面的栗子是将函数声明为依赖项,但这不是声明依赖项的唯一方法(尽管它会更常见)
    • 关键点应该是依赖项是 callable 可调用的
    • Python 中 callable 是像函数一样可以调用的对象

    typing 中的 Callable 教程

    面向对象 __call__() 教程

    看看 Depends() 的源码

    第一个参数依赖项类型是 Callable,必须是可调用对象

    类作为依赖项

    类是可调用对象吗?

    from typing import Callable
    
    
    class Cat:
        def __init__(self, name: str):
            self.name = name
    
    
    # 判断类对象是不是可调用对象
    print(isinstance(Cat, Callable))
    
    
    # 输出结果
    True

    所以类可以声明为依赖项!

    实际代码

    #!usr/bin/env python
    # -*- coding:utf-8 _*-
    """
    # author: 小菠萝测试笔记
    # blog:  https://www.cnblogs.com/poloyy/
    # time: 2021/9/24 7:58 下午
    # file: 26_class_dependency.py
    """
    
    from typing import Optional, Dict, Any
    # 2、导入 Depends
    from fastapi import Depends, FastAPI
    
    import uvicorn
    
    app = FastAPI()
    
    # 模拟数据库
    fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
    
    
    # 1、类作为依赖项
    class CommonQueryParams:
        # 仍然是三个参数
        def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100):
            self.q = q
            self.skip = skip
            self.limit = limit
    
    
    # 2、声明 Depends()
    @app.get("/items")
    async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
        response = {}
        # 模拟从数据库中读取数据
        items = fake_items_db[commons.skip: commons.skip + commons.limit]
        response.update({"items": items, "q": commons.q})
        return response
    
    
    if __name__ == "__main__":
        uvicorn.run(app="26_class_dependency:app", host="127.0.0.1", port=8080, reload=True, debug=True)

    重点

    • 发起请求的时候,需要根据 __init__() 的参数列表来传参
    • 请求数据将会传递到类的初始化方法中( __init__ )
    • commons 参数接收的值类型就是 CommonQueryParams

    正确传参的请求结果

    查看 Swagger API 文档

    类作为依赖项的三种写法

    commons: CommonQueryParams = Depends()
    commons: CommonQueryParams = Depends(CommonQueryParams)
    commons = Depends(CommonQueryParams)
    • 标准写法是第二种
    • 但推荐第一种,它是第二种写法的缩写
    • 不推荐第三种,因为参数没有指定类型,IDE 不会有代码智能提示

    commons: CommonQueryParams = Depends()

    • 这是 commons: CommonQueryParams = Depends(CommonQueryParams) 快捷编写方式
    • 如果依赖项是一个类,推荐用这种方式写,因为 FastAPI 会自动调用依赖项类,以创建类本身的实例对象

    依赖类的 __init__ 方法没有参数的栗子

    class NoInitClass:
        def __str__(self):
            return "hhh,重写了 str 方法"
    
    
    @app.get("/items2")
    async def read_items(
            # 用第一种推荐写法来声明依赖项
            commons: NoInitClass = Depends()
    ):
        return {"result": str(commons)}

    查看 Swagger API 文档

    请求结果

    依赖类的 __int__ 方法有参数的类型是 Dict、List 的栗子

    from typing import List, Dict, Any, Optional
    from fastapi import Depends
    from fastapi.encoders import jsonable_encoder
    
    
    # 依赖类
    class DictListClass:
        def __init__(self,
                     *,
                     name: str,
                     address: Optional[List[str]] = None,
                     info: Optional[Dict[str, Any]] = None,
                     ext: Optional[List[Dict[str, Any]]] = None
                     ):
            self.name = name
            self.address = address
            self.info = info
            self.ext = ext
    
        # 实例方法
        def test(self):
            self.info.update({"test_func": "调用方法添加的键值对"})
    
    
    @app.get("/items3")
    async def read_items(
            # 用第一种推荐写法来声明依赖项
            commons: DictListClass = Depends()
    ):
        # 打印下看看 commons 是什么
        print(commons, type(commons))
    
        # 调用实例方法
        commons.test()
    
        commons = jsonable_encoder(commons)
        # 打印转换后的 commons 是什么
        print(commons, type(commons))
        return {"commons": commons}

    查看 Swagger API 文档

    正确传参的请求结果

     

    请求后,查看控制台输出

    <26_class_dependency.DictListClass object at 0x10d20ff40> <class '26_class_dependency.DictListClass'>
    {'name': '小菠萝', 'address': ['广州', '深圳'], 'info': {'age': 24, 'test_func': '调用方法添加的键值对'}, 'ext': [{'sex': 'girl'}, {'phone': 135012121212}]} <class 'dict'>
    • 可以看到转换前,commons 就是一个 DictListClass 类实例对象
    • jsonable_encoder 转换后的 commons 就是一个 dict(jsonable_encoder 真是强大)

    用 commons: DictListClass = Depends() 声明依赖后的代码提示

    不仅代码优雅简洁一点,而且仍然有 IDE 代码提示

  • 相关阅读:
    js去除字符串空格(空白符)
    jq以固定开头的class属性的名称
    day--38 mysql表的完整性约束总结
    day--39-MySQL的多表查询
    day--40 mysql-视图,触发器,存储过程,函数总结
    day--41 mysql索引原理与慢查询优化
    day--42 前端基础小结
    day--43 HTML标签和CSS基本小结
    day46----JavaScript的函数及对象小结
    JavaScript正则表达式
  • 原文地址:https://www.cnblogs.com/poloyy/p/15332555.html
Copyright © 2011-2022 走看看