在深入研究Dependency Injection系统之前,让我们升级前面的示例。
之前例子中的dict
在前面的示例中,我们从依赖项(“ dependable”)中返回了一个字典:
from fastapi import Depends, FastAPIapp = FastAPI()async def common_parameters(q: str = None, skip: int = 0, limit: int = 100):return {"q": q, "skip": skip, "limit": limit}@app.get("/items/")async def read_items(commons: dict = Depends(common_parameters)):return commons@app.get("/users/")async def read_users(commons: dict = Depends(common_parameters)):return commons
但是,然后我们得到了从路径操作函数得到了的一个带有参数common变量dict。
而且我们知道编辑器无法为字典提供很多支持(例如完成),因为他们不知道其键和值类型。我们可以做得更好…
是什么导致了依赖
到现在为止,您已经看到依赖项声明为函数。
但这不是声明依赖关系的唯一方法(尽管可能更常见)。
关键因素是依赖项应该是“可调用的”。
Python中的“可调用”是Python可以像函数一样“调用”的任何东西。
因此,如果您有一个对象(可能不是函数),则可以像下面这样“调用”(执行)该对象:
something()
或者
something(some_argument, some_keyword_argument="foo")
类作为依赖
您可能会注意到,使用相同的语法来创建Python类的实例。
例如:
class Cat:def __init__(self, name: str):self.name = namefluffy = Cat(name="Mr Fluffy")
在这种情况下,fluffy是Cat类的实例。
为了创建fluffy,您是在“调用”Cat。
因此,Python类也是可调用的。
然后,在FastAPI中,您可以使用Python类作为依赖项。
FastAPI实际检查的是它是“可调用的”(函数,类或其他任何东西),并且已定义参数。
如果在FastAPI中将“可调用”作为依赖项传递,它将分析该“可调用”的参数,并以与路径操作函数的参数相同的方式处理它们。包括子依赖项。
这也适用于根本没有参数的可调用对象。与没有参数的路径操作功能相同。
然后,我们可以将依赖项“dependable” common_parameters从上面更改为类CommonQueryParameters:
from fastapi import Depends, FastAPIapp = FastAPI()fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]class CommonQueryParams:def __init__(self, q: str = None, skip: int = 0, limit: int = 100):self.q = qself.skip = skipself.limit = limit@app.get("/items/")async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):response = {}if commons.q:response.update({"q": commons.q})items = fake_items_db[commons.skip : commons.skip + commons.limit]response.update({"items": items})return response
注意用于创建类实例的__init__方法:
from fastapi import Depends, FastAPIapp = FastAPI()fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]class CommonQueryParams:def __init__(self, q: str = None, skip: int = 0, limit: int = 100):self.q = qself.skip = skipself.limit = limit@app.get("/items/")async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):response = {}if commons.q:response.update({"q": commons.q})items = fake_items_db[commons.skip : commons.skip + commons.limit]response.update({"items": items})return response
…其参数与之前的common_parameters相同:
from fastapi import Depends, FastAPIapp = FastAPI()async def common_parameters(q: str = None, skip: int = 0, limit: int = 100):return {"q": q, "skip": skip, "limit": limit}@app.get("/items/")async def read_items(commons: dict = Depends(common_parameters)):return commons@app.get("/users/")async def read_users(commons: dict = Depends(common_parameters)):return commons
这些参数是FastAPI将用于“解决”依赖关系的参数。
在这两种情况下,它都将具有:
- 可选的
q查询参数。 skip查询参数,默认值为0。limit查询参数,默认值为100。
在两种情况下,数据都将在OpenAPI架构上进行转换,验证和记录等。
使用它
现在,您可以使用此类声明依赖项。
并且当FastAPI调用该类时,将作为commons对象传递给您的函数的值将是该类的“实例”,因此您可以将参数commons对象声明为该类的类型CommonQueryParams。
from fastapi import Depends, FastAPIapp = FastAPI()fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]class CommonQueryParams:def __init__(self, q: str = None, skip: int = 0, limit: int = 100):self.q = qself.skip = skipself.limit = limit@app.get("/items/")async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):response = {}if commons.q:response.update({"q": commons.q})items = fake_items_db[commons.skip : commons.skip + commons.limit]response.update({"items": items})return response
类型注释与Depends
在上面的代码中,您将commons声明为:
commons: CommonQueryParams = Depends(CommonQueryParams)
最后一个CommonQueryParams,位于:
... = Depends(CommonQueryParams)
…是FastAPI实际用来了解依赖项的内容。
从这里开始,FastAPI将提取声明的参数,而这正是FastAPI实际调用的参数。
在这种情况下,第一个CommonQueryParams位于:
commons: CommonQueryParams ...
…对于FastAPI没有任何特殊含义。 FastAPI不会将其用于数据转换,验证等(因为它使用的是= Depends(CommonQueryParams))。
您实际上可以只写:
commons = Depends(CommonQueryParams)
在:
from fastapi import Depends, FastAPIapp = FastAPI()fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]class CommonQueryParams:def __init__(self, q: str = None, skip: int = 0, limit: int = 100):self.q = qself.skip = skipself.limit = limit@app.get("/items/")async def read_items(commons=Depends(CommonQueryParams)):response = {}if commons.q:response.update({"q": commons.q})items = fake_items_db[commons.skip : commons.skip + commons.limit]response.update({"items": items})return response
但是鼓励声明类型,因为这样您的编辑器将知道将作为参数公共变量传递的内容,然后它可以帮助您完成代码,进行类型检查等:
捷径
但是您会看到我们在这里有一些代码重复,两次编写CommonQueryParams:
commons: CommonQueryParams = Depends(CommonQueryParams)
FastAPI为这些情况提供了一种快捷方式,其中依赖项是FastAPI将“调用”以创建该类本身的实例的类。
对于这些特定情况,您可以执行以下操作:
无需编写:
commons: CommonQueryParams = Depends(CommonQueryParams)
你可以直接写:
commons: CommonQueryParams = Depends()
因此,您可以将依赖项声明为变量的类型,并使用Depends()作为该函数参数的“默认”值(=后面的值),而无需任何参数,而不必再次编写完整的类在Depends(CommonQueryParams)内部。
因此,相同的示例如下所示:
from fastapi import Depends, FastAPIapp = FastAPI()fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]class CommonQueryParams:def __init__(self, q: str = None, skip: int = 0, limit: int = 100):self.q = qself.skip = skipself.limit = limit@app.get("/items/")async def read_items(commons: CommonQueryParams = Depends()):response = {}if commons.q:response.update({"q": commons.q})items = fake_items_db[commons.skip : commons.skip + commons.limit]response.update({"items": items})return response
…并且FastAPI将知道该怎么做。
:::tips 这只是捷径。因为FastAPI关心帮助您最大程度地减少代码重复。 :::
