如何在路由装饰器中获取Request对象?

问题描述 投票:0回答:2

如何在装饰器中获取请求对象而不在路由中显式指定它?我已经有很多路由器了,我不想把

request: Request
放入每个路由器中。

工作原理:

def decorator_func(...):
    def decorator(func):
        @wraps(func)
        async def wrapper(request, *args, **kwargs):
            return await func(args, kwargs)

        return wrapper

    return decorator


@router.get(path='/something')
@decorator_func(...)
def get_something(request: Request):
    ...

我想要什么:

def decorator_func(...):
    def decorator(func):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            request = ... # GET request object
            return await func(args, kwargs)

        return wrapper

    return decorator


@router.get(path='/something')
@decorator_func(...)
def get_something(...):
    ...
python fastapi python-decorators
2个回答
1
投票

您可以使用路由装饰器的

dependencies
参数来调用特定的依赖项作为请求流的一部分,特别是当您不打算使用它们的返回值时。

通过在依赖项中使用

yield
,您可以在调用控制器之前和之后运行代码:

from fastapi import Depends, FastAPI, Request


app = FastAPI()


def conditional_dependency(request: Request):
    print(f"I'm before request {request}")
    yield 
    print(f"I'm after request {request}")


@app.get(path='/something', dependencies=[Depends(conditional_dependency)])
def get_something():
    print("This is the request itself")

这会导致输出:

I'm before request <starlette.requests.Request object at 0x0000021686F75240>
This is the request itself
I'm after request <starlette.requests.Request object at 0x0000021686F75240>

调用端点时。

当您想要将特定功能应用于整个路由器(而不是应用程序中的其他路由器)时,这也很有用:

from fastapi import APIRouter, Depends, FastAPI, Request


app = FastAPI()


def conditional_dependency(request: Request):
    print(f"I'm before request {request}")
    yield 
    print(f"I'm after request {request}")


router_with_dependency = APIRouter(
    dependencies=[Depends(conditional_dependency)]
)

app.mount('/foo', router_with_dependency)


@router_with_dependency.get(path='/something')
def get_something():
    print("This is the request itself")

/foo/something
发出请求将为在该路由器上注册的每个端点运行依赖项,而在应用程序对象或其他路由器上注册的端点不会自动调用它。


0
投票

扩展 Mats 的答案,如果您想要传递的数据是常量,您可以将装饰器包装在工厂函数中,然后您同时拥有请求和数据:

def dep_with_data(data: str):
    def conditional_dependency(request: Request):
        print(f"I'm before request {request}, data is {data}")
        yield
        print(f"I'm after request {request}, data is {data}")
    return conditional_dependency


@app.get(path='/something', dependencies=[Depends(dep_with_data("something"))])
def get_something():
    print("This is the request itself")


@app.get(path='/another', dependencies=[Depends(dep_with_data("another thing"))])
def get_another():
    print("This is the request itself")

如果这是您需要传递的唯一依赖项,您可以将更多内容移动到包装器以缩短每次使用它时的代码:

def dep_with_data(data: str):
    def conditional_dependency(request: Request):
        print(f"I'm before request {request}, data is {data}")
        yield
        print(f"I'm after request {request}, data is {data}")
    return {
        "dependencies": [Depends(conditional_dependency)]
    }


@app.get(path='/something', **dep_with_data("something"))
def get_something():
    print("This is the request itself")


@app.get(path='/another', **dep_with_data("another thing"))
def get_another():
    print("This is the request itself")
© www.soinside.com 2019 - 2024. All rights reserved.