我使用的是运行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
。
我尝试使用此命令
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"
是唯一的解决方案吗?
发布于 2021-01-11 23:11:58
出现该错误是因为Jupyter notebooks有一个正在运行的事件循环。来自documentation
如果您试图从有正在运行的事件循环的线程中运行这些部件中的任何一个,您将得到一个SynchronousOnlyOperation错误。请注意,您不必直接在异步函数内部就会发生此错误。如果您直接从异步函数调用同步函数,而没有经过诸如sync_to_async()或线程池之类的东西,那么也可能发生这种情况,因为您的代码仍在异步上下文中运行。如果遇到此错误,则应修复代码,使其不从异步上下文中调用有问题的代码;相反,应编写在异步不安全的同步函数中与其对话的代码,并使用asgiref.sync.sync_to_async()或在其自己的线程中运行同步代码的任何其他首选方法来调用该函数。如果你非常需要从异步环境中运行这段代码--例如,它是被外部环境强加给你的,并且你确信它没有并发运行的机会(例如,你在Jupyter笔记本上),那么你可以使用DJANGO_ALLOW_ASYNC_UNSAFE环境变量来禁用警告。
由于该问题特定于jupyter笔记本环境,因此以下是一个有效的解决方案。
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()
但是,根据文档警告,您需要小心,不要在生产环境中使用它。
发布于 2020-05-27 00:30:15
sync_to_async
接受callable,而不是结果。相反,你想要的是:
from asgiref.sync import sync_to_async
users = sync_to_async(User.objects.all)()
for user in users:
print(user)
您还可以将想要包装的调用放在修饰函数中:
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)
请注意,这必须在异步上下文中使用,因此完整的示例如下所示:
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)
发布于 2021-02-12 00:04:17
你不能在同步和异步函数之间传递查询集,因为它是惰性的。您需要在异步上下文中对其进行评估。
如下所示:
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())
https://stackoverflow.com/questions/61926359
复制相似问题