DRF中异步请求报错:TypeError: _SessionRequestContextManager无法用于await表达式
解决DRF中调用异步aiohttp代码的TypeError问题
首先,咱们先揪出错误的根源:TypeError: object _SessionRequestContextManager can't be used in 'await' expression这个报错,本质是你用错了aiohttp的请求方式,再加上DRF视图里的异步调用方式不当导致的。
aiohttp.request()返回的是一个上下文管理器对象(就是报错里的_SessionRequestContextManager),不是可以直接await的协程。你本地运行时可能因为aiohttp版本或者事件循环的巧合没触发问题,但到了DRF的环境里,这个用法的问题就直接暴露了。
第一步:修正aiohttp请求的写法
你需要用async with来正确管理aiohttp的请求上下文,这样不仅能解决报错,还能自动帮你关闭响应,不用手动调用response.close()了:
async def post1(data): async with aiohttp.request('post', 'http://你的目标接口地址', json=data) as response: return await response.json() async def get2(): async with aiohttp.request('get', 'http://你的目标接口地址') as response: return await response.json()
第二步:修正DRF视图里的异步调用方式
你现在是在同步DRF视图里手动创建并关闭事件循环,这其实是个坏主意——DRF所在的服务器(比如Django的开发服务器或者gunicorn)可能已经在运行自己的事件循环,你手动关闭会导致后续的异步操作出问题。
推荐的做法是把DRF视图改成异步视图(DRF 3.10及以上版本支持),这样可以直接在视图里await你的异步函数:
class MyViewSet(GenericAPIView): async def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # 直接await异步函数,不用手动管理事件循环 result = await asynchronous(serializer.data) # 这里可以根据业务需求返回result或者处理后的serializer数据 return Response(result, status=status.HTTP_201_CREATED)
如果因为某些原因必须用同步视图,那也不要手动操作事件循环,改用asyncio.run()(Python 3.7+支持)来执行异步代码:
class MyViewSet(GenericAPIView): def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) # 用asyncio.run代替手动管理事件循环 result = asyncio.run(asynchronous(serializer.data)) return Response(serializer.data, status=status.HTTP_201_CREATED)
最后再总结下问题点:
- 错误地直接
await了aiohttp的上下文管理器对象,没有用async with正确处理请求 - 在DRF同步视图中手动创建并关闭事件循环,容易和服务器的事件循环产生冲突
内容的提问来源于stack exchange,提问作者virvaldium
相关产品推荐
相关产品推荐

