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 是像函数一样可以调用的对象
看看 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 代码提示