在深入研究依赖注入系统之前,让我们升级前面的例子。
在前面的示例中,我们dict从我们的依赖项(“可靠”)中返回 a :
from typing import Optional
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: Optional[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
但是随后我们在路径操作函数dict的参数commons中得到了一个。
而且我们知道编辑器不能为dicts提供很多支持(比如补全),因为他们无法知道它们的键和值类型。
我们可以做得更好...
到目前为止,您已经看到了声明为函数的依赖项。
但这不是声明依赖项的唯一方法(尽管它可能更常见)。
关键因素是依赖项应该是“可调用的”。
Python 中的“可调用”是 Python 可以像函数一样“调用”的任何东西。
因此,如果您有一个对象something(可能不是函数)并且您可以“调用”它(执行它),例如:
something()
或者
something(some_argument, some_keyword_argument="foo")
那么它是一个“可调用的”。
您可能会注意到,要创建 Python 类的实例,您使用相同的语法。
例如:
class Cat:
def __init__(self, name: str):
self.name = name
fluffy = Cat(name="Mr Fluffy")
在这种情况下,fluffy是类的一个实例Cat。
而要创造fluffy,你就是在“呼唤” Cat。
因此,Python 类也是一个可调用的.
然后,在FastAPI 中,您可以使用 Python 类作为依赖项。
FastAPI 实际检查的是它是“可调用的”(函数、类或其他任何东西)和定义的参数。
如果在FastAPI 中传递“可调用”作为依赖项,它将分析该“可调用”的参数,并以与路径操作函数的参数相同的方式处理它们。包括子依赖。
这也适用于根本没有参数的可调用对象。与没有参数的路径操作函数相同。
然后,我们可以将依赖项“可靠”common_parameters从上面更改为类CommonQueryParams:
from typing import Optional
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.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 typing import Optional
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.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 typing import Optional
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: Optional[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将用来“解决”依赖关系的。
在这两种情况下,它将具有:
在这两种情况下,数据都将被转换、验证、记录在 OpenAPI 模式等上。
现在您可以使用此类声明您的依赖项。
from typing import Optional
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.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
FastAPI调用CommonQueryParams该类。这将创建该类的“实例”,并且该实例将作为参数传递commons给您的函数。
注意我们CommonQueryParams在上面的代码中是如何写两次的:
commons: CommonQueryParams = Depends(CommonQueryParams)
最后CommonQueryParams,在:
... = Depends(CommonQueryParams)
...是FastAPI实际用来知道什么是依赖项的。
FastAPI 将从中提取声明的参数,这就是 FastAPI 将实际调用的内容。
在这种情况下,第一个CommonQueryParams, 在:
commons: CommonQueryParams ...
...对FastAPI没有任何特殊含义。FastAPI 不会将它用于数据转换、验证等(因为它正在= Depends(CommonQueryParams)为此使用 )。
你实际上可以只写:
commons = Depends(CommonQueryParams)
..如:
from typing import Optional
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.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
但是鼓励声明类型,因为这样您的编辑器将知道将作为参数传递的内容commons,然后它可以帮助您完成代码完成、类型检查等:
但是你看到我们这里有一些代码重复,写了CommonQueryParams两次:
commons: CommonQueryParams = Depends(CommonQueryParams)
FastAPI为这些情况提供了一种快捷方式,在这种情况下,依赖项特别是一个类,FastAPI将“调用”以创建类本身的实例。
对于这些特定情况,您可以执行以下操作:
而不是写:
commons: CommonQueryParams = Depends(CommonQueryParams)
...你写:
commons: CommonQueryParams = Depends()
你声明依赖作为参数的类型,并使用Depends()其“默认”值(即后=),该函数的参数,在没有任何参数Depends(),而不必编写完整的类再次里面的Depends(CommonQueryParams)。
同样的例子看起来像:
from typing import Optional
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.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会知道该怎么做。
提示
如果这看起来更令人困惑而不是有用,请忽略它,您不需要它。
这只是一个捷径。因为FastAPI关心帮助您最大程度地减少代码重复。