【10.0】依赖注入系统
【一】引入
【1】介绍
- “依赖注入”是指在编程中,为保证代码成功运行,先导入或声明其所需要的 “依赖”,如子函数、数据库连接等
【2】优势
- 提高代码的复用率
- 共享数据库的连接
- 增强安全、认证和角色管理
【3】FastAPI的兼容性
- 所有的关系型数据库,支撑NoSQL数据库
- 第三方的包和API
- 认证和授权系统
- 响应数据注入系统
【二】创建、导入和声明依赖
【1】创建
from fastapi import APIRouter, Depends
from typing import Optional
app05 = APIRouter()
# 创建公共函数
async def common_parameters(q: Optional[str] = None, page: int = 1, limit: int = 100):
return {"q": q, "page": page, "limit": limit}
【2】导入和声明
# 定义视图
@app05.get('/dependency01')
async def dependency01(commons: dict = Depends(common_parameters)):
return commons
# 可以在async def中调用def依赖,也可以在def中导入async def依赖
@app05.get('/dependency02')
def dependency01(commons: dict = Depends(common_parameters)):
return commons
【3】使用
- async def中调用def依赖
- def中导入async def依赖
【三】类作为依赖项
【1】定义视图
from fastapi import APIRouter, Depends
from typing import Optional
app05 = APIRouter()
"""Classes as Dependencies 类作为依赖项"""
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: Optional[str] = None, page: int = 1, limit: int = 100):
self.q = q
self.page = page
self.limit = limit
@app05.get("/classes_as_dependencies")
# 写法一
# async def classes_as_dependencies(commons: CommonQueryParams = Depends(CommonQueryParams)):
# 写法二
# async def classes_as_dependencies(commons: CommonQueryParams = Depends()):
#写法三
async def classes_as_dependencies(commons=Depends(CommonQueryParams)):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.page: commons.page + commons.limit]
response.update({"items": items})
return response
【2】发起请求
【四】子依赖的创建和调用
【1】定义视图
from fastapi import APIRouter, Depends
from typing import Optional
app05 = APIRouter()
"""Sub-dependencies 子依赖"""
def query(q: Optional[str] = None):
return q
def sub_query(q: str = Depends(query), last_query: Optional[str] = None):
if not q:
return last_query
return q
@app05.get("/sub_dependency")
async def sub_dependency(final_query: str = Depends(sub_query, use_cache=True)):
"""use_cache默认是True, 表示当多个依赖有一个共同的子依赖时,每次request请求只会调用子依赖一次,多次调用将从缓存中获取"""
return {"sub_dependency": final_query}
【2】发起请求
【五】路径装饰器中的多依赖
【1】定义视图
from fastapi import APIRouter, Depends, HTTPException, Header
from typing import Optional
app05 = APIRouter()
"""Dependencies in path operation decorators 路径操作装饰器中的多依赖"""
async def verify_token(x_token: str = Header(...)):
"""没有返回值的子依赖"""
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
async def verify_key(x_key: str = Header(...)):
"""有返回值的子依赖,但是返回值不会被调用"""
if x_key != "fake-super-secret-key":
raise HTTPException(status_code=400, detail="X-Key header invalid")
return x_key
@app05.get("/dependency_in_path_operation",
# 这时候不是在函数参数中调用依赖,而是在路径操作中
dependencies=[Depends(verify_token), Depends(verify_key)])
async def dependency_in_path_operation():
return [{"user": "user01"}, {"user": "user02"}]
【2】发起请求
- token 和 key 都不相符的情况
- token 相符 key 不相符
- token 和 key 都相符
【六】全局依赖的使用
"""Global Dependencies 全局依赖"""
# 单独在某个路由下的全局使用
app05 = APIRouter(dependencies=[Depends(verify_token), Depends(verify_key)])
# 也可以放在全局的总app下
【七】使用yield的依赖和子依赖
这个需要Python3.7才支持,
Python3.6需要pip install async-exit-stack async-generator
- 伪代码示例
from fastapi import APIRouter, Depends, HTTPException, Header
from typing import Optional
app05 = APIRouter()
# 以下都是伪代码
async def get_db():
db = "db_connection"
try:
# 使用数据库
yield db
finally:
# 关闭数据库
db.endswith("db_close")
async def dependency_a():
dep_a = "generate_dep_a()"
try:
# 使用依赖 a
yield dep_a
finally:
# 关闭依赖 数据库
dep_a.endswith("db_close")
async def dependency_b(dep_a=Depends(dependency_a)):
dep_b = "generate_dep_b()"
try:
# 使用依赖 b
yield dep_b
finally:
# 关闭依赖 a
dep_b.endswith(dep_a)
async def dependency_c(dep_b=Depends(dependency_b)):
dep_c = "generate_dep_c()"
try:
# 使用依赖 c
yield dep_c
finally:
# 关闭依赖 b
dep_c.endswith(dep_b)
本文来自博客园,作者:Chimengmeng,转载请注明原文链接:https://www.cnblogs.com/dream-ze/p/17738896.html