Django: SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async

Regis Santos picture Regis Santos · May 21, 2020 · Viewed 12.1k times · Source

I use Django 3.0.6 and Jupyter notebook running with shell_plus --notebook.

I try run queryset:

User.objects.all()

But return this error SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.

I try this command

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

The solution of Django documentation

os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true" in settings.py is the unique solution?

Answer

Tom Carrick picture Tom Carrick · May 26, 2020

sync_to_async takes a callable, not the result. Instead, you want this:

from asgiref.sync import sync_to_async

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

for user in users:
    print(user)

You can also put the call(s) you want to wrap in a decorated function:

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)

Note that this must be used from an async context, so a full example would look like:

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