【问题标题】:How to use async function based views in DRF?如何在 DRF 中使用基于异步函数的视图?
【发布时间】:2023-03-27 10:50:01
【问题描述】:

由于 Django 现在支持异步视图,我正在尝试将包含许多基于函数的视图的代码库更改为异步但由于某种原因它无法正常工作。

@api_view(["GET"])
async def test_async_view(request):
    ...
    data = await get_data()
    return Response(data)

当我向此端点发送请求时,我收到一条错误消息:

AssertionError:应为 ResponseHttpResponseHttpStreamingResponse 要从视图中返回,但收到一个 <class 'coroutine'>

DRF 还不支持异步视图吗?我可以做些什么来让它工作吗?

【问题讨论】:

    标签: python django asynchronous django-rest-framework


    【解决方案1】:

    截至目前,DRF 不支持异步“api 视图”。这是 DRF 社区中的公开issue (#7260),目前仍处于讨论阶段。

    但是,Django 提供了一个装饰器/包装器,它允许我们使用 sync_to_async(...) 包装器将我们的同步视图/函数转换为异步。

    例子,

    @sync_to_async
    @api_view(["GET"])
    def sample_view(request):
        data = get_data()
        return Response(data)

    请注意,这里的sample_view(...)get_data(...) 是同步函数。

    【讨论】:

    • 这有什么帮助?如果 get_data 是同步的?
    • 正如我所提到的,DRF 不支持“异步 API 视图*。最少的解决方法是使用 sync_to_async(...)。这意味着 sample_view(...) 必须是sync 函数,因此get_data(...) 也应该是一个同步函数。
    • 我也对此感到困惑。如果get_data() 是大部分工作并且必须同步,那么@sync_to_async 可能实现什么?
    【解决方案2】:

    我认为你可以在 DRF 中使用这个装饰器

    import asyncio
    from functools import wraps
    
    
    def to_async(blocking):
        @wraps(blocking)
        def run_wrapper(*args, **kwargs):
            return asyncio.run(blocking(*args, **kwargs))
    
        return run_wrapper
    

    使用示例

    @to_async
    @api_view(["GET"])
    async def sample_view(request):
        ...
    

    【讨论】:

    • 不要在 Django 中使用asyncio.run,因为它允许asgiref.sync.sync_to_async 函数按预期工作(需要围绕数据库调用)请改用asgiref.sync.async_to_sync
    猜你喜欢
    • 2020-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-20
    • 2020-07-31
    • 2023-04-08
    相关资源
    最近更新 更多