阅读(4766) (0)

FastAPI教程 作为依赖的类

2021-11-02 17:01:46 更新

在深入研究依赖注入系统之前,让我们升级前面的例子。

来自上一个示例的一个字典

在前面的示例中,我们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将用来“解决”依赖关系的。

在这两种情况下,它将具有:

  • 一个可选的q查询参数是str.
  • 一个skip查询参数是int,用的默认0。
  • 一个limit查询参数是int,用的默认100。

在这两种情况下,数据都将被转换、验证、记录在 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给您的函数。

类型注释与 Depends

注意我们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关心帮助您最大程度地减少代码重复。