Django异步环境调用objects.all()遍历报错如何解决?
问题解决方法
报错原因
Django ORM默认是同步实现,所有数据库查询、QuerySet迭代操作都会触发同步IO,无法直接在异步协程上下文执行,所以会抛出You cannot call this from an async context - use a thread or sync_to_async.错误。
解决方案
方案1:使用sync_to_async封装同步ORM逻辑(兼容所有Django版本)
借助asgiref自带的sync_to_async工具,把所有ORM相关的同步逻辑封装为异步可调用对象,在协程中await执行即可。
修改Monitoring/chat.py代码如下:
import asyncio from asgiref.sync import sync_to_async from Monitoring.models import User # 把ORM操作全部放在同步函数内 def query_all_users(): # 直接转为list执行查询,避免QuerySet懒加载在异步上下文触发报错 return list(User.objects.all()) async def handle(): while True: # 异步执行同步查询逻辑 users = await sync_to_async(query_all_users)() for user in users: print(user.user_id) await asyncio.sleep(60)
方案2:使用Django原生异步ORM接口(Django 3.1及以上版本支持)
Django 3.1之后官方提供了异步ORM方法,在原有方法名前加前缀a即可直接在协程中调用,无需自行封装:
修改Monitoring/chat.py代码如下:
import asyncio from Monitoring.models import User async def handle(): while True: # 调用异步查询方法aall()直接获取结果 users = await User.objects.aall() for user in users: print(user.user_id) await asyncio.sleep(60)
如果涉及增删改操作,对应使用asave()、adelete()、aupdate()等异步方法即可。
注意事项
- QuerySet是懒加载的,仅调用
all()不会触发数据库查询,迭代时才会真正执行,不要将未执行的QuerySet返回到异步上下文进行迭代,否则仍会报错。 - 复杂的ORM查询逻辑如果没有对应异步方法,统一用
sync_to_async封装整个查询逻辑即可。
内容的提问来源于stack exchange,提问作者SKC
相关产品推荐
相关产品推荐

