前言
依赖注入系统,可以说是fastapi框架中很重要也是一个核心的系统。因为fastapi主要用的都是函数式编程实现API的方式,不像Django里面,有FBV和CBV。为了实现和Django一样的视图编程方式,于是就引入了这个依赖注入的概念。
依赖注入的优势:
- 提高代码的复用率,一些公共的资源,比如,函数,提取出来复用,一些pydantic验证也是如此。
- 共享数据库连接,避免操作数据库CURD时创造多条连接。
- 增强安全、认证和角色管理,就比如,超级管理员拥有什么权限。管理员拥有超级管理员之中的某些权限,而用户又只拥有管理员之下的某些权限。
从这个fastapi框架的角度来看,他的兼容性也是非常的强大的。通过依赖注入系统,可以支持SQL数据库,和NoSQL数据库。
声明依赖项
我们不以复杂的理论和代码来论证这个依赖注入,我们声明一个函数,用来当作依赖项来进行讲解。
async def common_parameters(q: Optional[str] = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
这里,我们声明了一个函数,有三个参数,q
、skip
、limit
,我没有对他进行任何处理,只是原封不动的返回了,如果在真实的开发场景中,我们如果把所有的业务处理全部放在一个函数中,那就成了祖传代码,除了你自己,几乎别人没人看得懂。(PS:你自己也不一定看得懂了~~(●’◡’●))
好了,回到我们这个场景,假如,我们要多次传入这三个参数,我们按照正常来说,也可以这么写:
async def test1(q: Optional[str] = None, skip: int = 0, limit: int = 100)
async def test2(q: Optional[str] = None, skip: int = 0, limit: int = 100)
然后,你会发现你的代码重复了,如果要进行相同的校验或者业务逻辑处理,需要更加繁琐的代码,也是需要一一重复。
这时候,我们把这个当作依赖,直接注入到函数中,就会减少重复。
@app.get('/')
async def test(common_parameters:dict = Depends(common_parameters)):
return common_parameters
这样,我们同样传入这三个参数,但是,在这个函数中,相应的减少了一些业务代码的处理。
类作为依赖项
fastapi不只是可以将函数作为依赖项,一切可以被称为资源的,都可以作为依赖项。比如,类。用法,几乎是一致的。
class common_parameters:
def __init__(self,q:Optional[str] = None,skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get('/')
async def test(common_parameters:dict = Depends(common_parameters)):
return common_parameters
子依赖
可以理解为类的继承, 声明了一个依赖项,经过一些处理后,再被另一个依赖给处理,有点像二次加工
# 声明一个子依赖项
def query_extractor(q: Optional[str] = None):
return q
# 声明第二个依赖项,将子依赖作为依赖注入
def query_or_cookie_extractor(
q: str = Depends(query_extractor), last_query: Optional[str] = Cookie(None)
):
if not q:
return last_query
return q
# 最后传到的
@app.get("/items/")
async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):
return {"q_or_cookie": query_or_default}
路径中操作依赖项
在路径中,无论是fastapi项目的实例还是APIrouter的实例,所导的路径装饰器中,都可以进行依赖的注入。在路由中,使用
dependencies
来进行依赖的注入。他可以是一个Depends
,也可以是一个列表,来进行多个依赖项的注入
# 声明两个依赖
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
# 在路由装饰器中,列表形式注入多个依赖项
@app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)])
async def read_items():
return [{"item": "Foo"}, {"item": "Bar"}]
全局依赖
在全局中,无论是
APIRouter
还是FastAPI
,他们所实例的变量都可以通过dependencies
来进行依赖的注入,这样,所有使用了他们的路由装饰器,都会进行其依赖的操作。
# 在FastAPI中使用依赖注入
app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)])
# 在APIRouter中使用
apirouter = APIRouter(dependencies=[Depends(verify_token), Depends(verify_key)])
关于fastapi
对于fastapi,我个人把他分成了几个部分,如果有感觉模糊不清的道友,可以参照这个思路,fastapi就非常的好理解了。
- 验证部分
这里分为了几个验证部分,分别为:Body、Header、Path、Query、Cookie
,其中,Body包括了pydantic,这里需要注意的一点就是,pydantic和fastapi不是一体的。不要搞混了。- 请求部分
关于对请求的处理,这里也包括了对Path的验证- 依赖注入系统
这个就不用多说了,😄- 响应处理
包括json、表单、文件等请求或者响应,这个不应该单独分出来,应该是和请求部分一致学习的- 认证授权数据库等
只要是好好的给他分割开来,逐一击破,对于新的框架学习来说,学习成本实际上并没有这么的高。
- Post link: https://www.godhearing.cn/fastapi-xue-xi-zhi-lu-4-yi-lai-zhu-ru/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.