如何在 DRF 中使用基于异步函数的视图?

nin*_*alt 28 python django asynchronous django-rest-framework

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

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

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

AssertionError: 期望从视图返回 Response,HttpResponse或 ,但收到了HttpStreamingResponse<class 'coroutine'>

DRF 还不支持异步视图吗?我可以采取其他替代方法来使其正常工作吗?

JPG*_*JPG 11

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

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

例子,

@sync_to_async
@api_view(["GET"])
def sample_view(request):
    data = get_data()
    return Response(data)
Run Code Online (Sandbox Code Playgroud)

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

  • 我也对此感到困惑。如果 `get_data()` 是大部分工作并且必须同步,那么 `@sync_to_async` 可以实现什么? (13认同)
  • 这有什么帮助?如果 get_data 是同步的? (3认同)

Mar*_*rty 6

你可以这样做adrf

pip install adrf
Run Code Online (Sandbox Code Playgroud)

然后将其添加到 INSTALLED_APPS

INSTALLED_APPS = [
    ...
    'adrf',
]
Run Code Online (Sandbox Code Playgroud)
import asyncio
from asgiref.sync import sync_to_async

@sync_to_async  
def do_a_network_call(some_input):  
    expensive_result = do_expensive_network_call(some_input)
    return expensive_result
    
# Class Based Views:
from adrf.views import APIView

class AsyncView(APIView):
    async def get(self, request):
        result = await asyncio.gather(do_a_network_call("some_input"))  
        return Response({"result": result})


# Function Based Views:
from adrf.decorators import api_view

@api_view(['GET'])
async def async_view(request):
    result = await asyncio.gather(do_a_network_call("some_input"))
    return Response({"result": result})
Run Code Online (Sandbox Code Playgroud)