首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Django: SynchronousOnlyOperation:您不能从异步上下文调用它-使用线程或sync_to_async

Django: SynchronousOnlyOperation:您不能从异步上下文调用它-使用线程或sync_to_async
EN

Stack Overflow用户
提问于 2020-05-21 10:50:46
回答 5查看 20.6K关注 0票数 29

我使用的是运行shell_plus --notebook的Django 3.0.6和Jupyter笔记本。

我尝试运行queryset:

User.objects.all()

但是返回这个错误SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async

我尝试使用此命令

代码语言:javascript
运行
复制
from asgiref.sync import sync_to_async

users = sync_to_async(User.objects.all())

for user in users:
    print(user)

TypeError: 'SyncToAsync' object is not iterable

Django文档的解决方案

settings.py中的os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"是唯一的解决方案吗?

EN

回答 5

Stack Overflow用户

发布于 2021-01-11 23:11:58

出现该错误是因为Jupyter notebooks有一个正在运行的事件循环。来自documentation

如果您试图从有正在运行的事件循环的线程中运行这些部件中的任何一个,您将得到一个SynchronousOnlyOperation错误。请注意,您不必直接在异步函数内部就会发生此错误。如果您直接从异步函数调用同步函数,而没有经过诸如sync_to_async()或线程池之类的东西,那么也可能发生这种情况,因为您的代码仍在异步上下文中运行。如果遇到此错误,则应修复代码,使其不从异步上下文中调用有问题的代码;相反,应编写在异步不安全的同步函数中与其对话的代码,并使用asgiref.sync.sync_to_async()或在其自己的线程中运行同步代码的任何其他首选方法来调用该函数。如果你非常需要从异步环境中运行这段代码--例如,它是被外部环境强加给你的,并且你确信它没有并发运行的机会(例如,你在Jupyter笔记本上),那么你可以使用DJANGO_ALLOW_ASYNC_UNSAFE环境变量来禁用警告。

由于该问题特定于jupyter笔记本环境,因此以下是一个有效的解决方案。

代码语言:javascript
运行
复制
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rest.settings')
os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
django.setup()
    
from users.models import User
User.objects.all()

但是,根据文档警告,您需要小心,不要在生产环境中使用它。

票数 26
EN

Stack Overflow用户

发布于 2020-05-27 00:30:15

sync_to_async接受callable,而不是结果。相反,你想要的是:

代码语言:javascript
运行
复制
from asgiref.sync import sync_to_async

users = sync_to_async(User.objects.all)()

for user in users:
    print(user)

您还可以将想要包装的调用放在修饰函数中:

代码语言:javascript
运行
复制
from asgiref.sync import sync_to_async

@sync_to_async
def get_all_users():
    return User.objects.all()

for user in await get_all_users():
    print(user)

请注意,这必须在异步上下文中使用,因此完整的示例如下所示:

代码语言:javascript
运行
复制
from asgiref.sync import sync_to_async

@sync_to_async
def get_all_users():
    return User.objects.all()

async def foo(request):
    for user in await get_all_users():
        print(user)

Full documentation

票数 22
EN

Stack Overflow用户

发布于 2021-02-12 00:04:17

你不能在同步和异步函数之间传递查询集,因为它是惰性的。您需要在异步上下文中对其进行评估。

如下所示:

代码语言:javascript
运行
复制
from django.contrib.auth.models import User
from asgiref.sync import sync_to_async
import asyncio


@sync_to_async
def get_users():
    return list(
        User.objects.all()
    )

async def user_loop():
    results = await get_users()
    for r in results:
        print(r.username)


loop = asyncio.get_event_loop()
loop.run_until_complete(user_loop())
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61926359

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档