Django异步if/else分支调用ORM报错:You cannot call this from an async context
问题原因
- Django ORM的
QuerySet是懒加载对象:调用filter()方法时并不会立刻执行数据库查询,只有当你对QuerySet做迭代、打印、调用len()/first()/count()等操作时,才会实际触发数据库请求。 - 你封装的
filter_data方法虽然加了@database_sync_to_async装饰器,但该方法仅返回了未执行的QuerySet对象,实际查询并没有在同步线程中执行。 - 分支表现差异的核心原因:if分支中拿到
model对象后没有做任何触发查询的操作,因此不会报错;else分支中执行了print(model),该操作会触发数据库查询,而查询动作直接在异步上下文中执行,没有经过同步封装,因此抛出异常。你修改分支逻辑后触发报错的分支都是会执行print(model)的分支,和判断条件本身没有关系。
解决方案
方案1:在同步封装方法内直接触发查询(推荐)
修改filter_data方法,在同步上下文内完成数据库查询,返回已经加载好的结果而非懒加载QuerySet,示例代码:
@database_sync_to_async def filter_data(**kwargs): # 转list触发查询执行,也可以根据业务需求调用first()/count()等 return list(FinishAnimateModel.objects.filter(**kwargs))
如果需要返回单个对象可以调整为:
@database_sync_to_async def filter_data(**kwargs): return FinishAnimateModel.objects.filter(**kwargs).first()
方案2:对后续QuerySet操作单独做同步封装
如果业务场景需要保留QuerySet对象,那么所有对该QuerySet的操作都需要用database_sync_to_async额外封装,示例:
# 单独封装打印/访问QuerySet的方法 @database_sync_to_async def print_model(model): print(model, 'model') # 调用处修改 async def receive(self, text_data=None, bytes_data=None): ... if data['msg']: print('in') model = await DB.Myself.filter_data(name__contains='') print('ok') else: print('else') model = await DB.Myself.filter_data(name__contains='') await print_model(model)
内容的提问来源于stack exchange,提问作者dudulu
相关产品推荐
相关产品推荐

