Python上的FastAPI依赖注入问题 [英] Dependency Injection problem with FastAPI on Python

查看:147
本文介绍了Python上的FastAPI依赖注入问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

美好的一天!请告诉我如何使用Python + FastAPI解决以下问题.

Good day! Please tell me how you can solve the following problem in Python + FastAPI.

有一个测试项目:

app / main.py - main file
app / routes / users.py -set of api methods
app / repos / factory.py - repository factory
app / repos / user_repository.py - repositories
app / handlers / factory.py - handler factory
app / handlers / users.py - handlers
app / domain / user.py - data class

main和route结构与示例 https://fastapi相同.tiangolo.com/tutorial/bigger-applications/

The main and routes structure is the same as in the example https://fastapi.tiangolo.com/tutorial/bigger-applications/

routes/users.py文件中:

from fastapi import APIRouter, Depends
from ..handlers import factory

router = APIRouter()

@router.get("/users/", tags=["users"])
def read_users(handler=Depends(factory.get_handler)):
    return handler.get_all()

handlers/factory.py 中:

from fastapi import Depends
from .users import UserHandler1

def get_handler(handler=Depends(UserHandler1)):
    return handler

handlers/users.py 中:

from fastapi import Depends
from ..repos import factory

class UserHandler1:
    def __init__(self):
        pass

    def get_all(self, repo=Depends(factory.get_repo)):
        return repo.get_all()

repos/factory.py :

from fastapi import Depends
from ..repos.user_repository import UserRepository

def get_repo(repo=Depends(UserRepository)):
    return repo

repos/user_repository.py :

from ..domain.user import User

class UserRepository:
    def __init__(self):
        pass

    def get_all(self):
        return [User(1, 'A'), User(2, 'B'), User(3, 'C')]

domain/user.py :

class User:
    id: int
    name: str

    def __init__(self, id, name):
        self.id = id
        self.name = name

然后我运行hypercorn服务器: app.main:app --reload 尝试调用api方法: http://127.0.0.1:8000/users/并得到错误AttributeError:'Depends'对象没有属性'get_all'

Then I run hypercorn server: app.main:app --reload Try call api method: http://127.0.0.1:8000/users/ And get the error AttributeError: 'Depends' object has no attribute 'get_all'

如果您删除处理程序层并执行此操作,则一切正常.

If you remove the handlers layer and do this, then everything will work.

routes/users.py:

from fastapi import APIRouter, Depends
from ..repos import factory

router = APIRouter()

@router.get("/users/", tags=["users"])
def read_users(repo=Depends(factory.get_repo)):
    return repo.get_all()
It also works if you completely remove all Depends and create
UserRepository and UserHandler1 directly in factories.

问题1:在这种情况下,为什么它不起作用?

Question 1: How do I use "Depends" in this case and why doesn't it work?

通常,工厂看起来不是解决此问题的好方法.我看到了使用多重继承的DI实现的示例,但就我而言,它与工厂方法相同.我还尝试使用Pinject库,但是它需要图形的初始构造,该图需要保存在某个地方以便在api处理程序中访问它.

In general, the factory does not look like a good solution to this problem. I saw an example of DI implementation using multiple inheritance but as for me it is the same as factory method. I also tried to use the Pinject library, but it requires the initial construction of a graph, which needs to be saved somewhere in order to access it in api handlers.

问题2(更重要)::在这种情况下如何应用依赖注入?

Question 2 (more important): How Dependency Injection can be applied in this case ?

推荐答案

如注释中所述,依赖关系可以是任何可调用的东西,因此也可以是一个类.在后一种情况下,唯一的警告是该类将仅被初始化(即,仅会调用 init (..)函数).

As noted in the comments, a dependency can be anything that is a callable and thus a class as well. The only caveat in the latter case is that the class will only be initialized (i.e. only the init(..) function will be called).

因此,为了将类作为依赖项,例如

So, in order to have a class as dependency, as in the example of https://fastapi.tiangolo.com/tutorial/dependencies/classes-as-dependencies/#shortcut you just need to call the target functions within the init and set the values as attributes of the class.

from ..domain.user import User

class UserRepository:
    def __init__(self):
        self.get_all()

    def get_all(self):
        self.users = [User(1, 'A'), User(2, 'B'), User(3, 'C')]


from fastapi import Depends
from ..repos.user_repository import UserRepository

def get_repo(repo=Depends(UserRepository)):
    print(repo.users) # This will print the list of users
    return repo

问题2

NB

这是一个建模问题.在这里,我提出我相信的是从 的角度来看很合适.它不一定必须最好还是最简单的方法.

This is a modelling question. Here I propose what I believe is suitable from my point of view. It does not necessarily have to be best or simplest approach.

回答您的第二个问题,对于这种复杂的依赖关系,我不建议.如果依赖项在路由器级别,则只需使用参数 depends = [...] 并提供依赖项类别/功能列表,即可将它们添加到路由器.

Answering your second question, I would not advice for such complex dependencies. If the dependencies are at the router level, you can simply add them to the router, using the parameter depends=[...] and providing a list of dependency classes/functions.

或者,您可以像对工厂所做的那样,将所有依赖项声明为端点的功能参数.这种方法可能会导致大量代码被复制和粘贴,因此我建议您采用上述方法.

Alternatively, you could declare all of the dependencies as function parameters of the endpoint, as you did for the factory. This method may lead to big chunks of code getting copied and pasted, so I advise for the above approach.

如果需要处理数据参数,则将它们添加到请求中并从端点内访问它们.请参见 FastAPI从API密钥获取用户ID ,作为一个最小的示例.

If you need to process the data parameters, then you add them to the request and access them from within the endpoint. See FastAPI get user ID from API key for a minimal example.

这篇关于Python上的FastAPI依赖注入问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆