解决Django异步视图中SynchronousOnlyOperation报错问题
问题解决:Django异步视图中SynchronousOnlyOperation报错
问题原因
你遇到的报错核心是QuerySet的惰性求值特性:虽然用@sync_to_async包装了查询函数,但filter()返回的QuerySet并没有立即执行数据库查询,而是等到模板中执行{% for education in educations %}遍历操作时,才触发实际的数据库请求——此时代码处于异步视图的上下文环境中,同步的数据库操作直接触发了SynchronousOnlyOperation异常。
而返回[Education.objects.first()]能正常运行,是因为first()会立即执行数据库查询,返回的是具体的模型实例,模板遍历仅访问实例属性(未触发新的同步数据库操作),因此不会报错。
解决方法
方法1:在同步函数中强制求值QuerySet
修改get_educations函数,将QuerySet转换为列表,让数据库查询在sync_to_async包裹的同步线程内完成:
@sync_to_async def get_educations(): # 用list()强制执行查询,返回普通列表而非惰性QuerySet return list(Education.objects.filter(highlight=True).order_by("-order")) async def home(request): return render(request, "home.html", { "educations": await get_educations(), })
方法2:使用Django异步ORM(Django 3.1+支持)
如果你的Django版本≥3.1,可以直接使用官方提供的异步查询方法,无需手动包装同步函数:
async def home(request): # 用afetch_all()强制执行异步查询,返回结果列表 educations = await Education.objects.filter(highlight=True).order_by("-order").afetch_all() return render(request, "home.html", { "educations": educations, })
注意:异步ORM的方法均以
a开头(如afilter、aget),必须在异步函数内调用。
内容的提问来源于stack exchange,提问作者Alberto Sanmartin Martinez
相关产品推荐
相关产品推荐

