6

Since 3.1 (currently beta) Django have support for async views

async def myview(request):
    users = User.objects.all()

This example will not work - since ORM is not yet async ready

so what's the current workaround ?

you cannot just use sync_to_async with queryset - as they it is not evaluated:

from asgiref.sync import sync_to_async

async def myview(request):
    users = await sync_to_async(User.objects.all)()

so the only way is evaluate queryset inside sync_to_async:

async def myview(request):
    users = await sync_to_async(lambda: list(User.objects.all()))()

which looks very ugly

any thoughts on how to make it nicer ?

Alasdair
  • 298,606
  • 55
  • 578
  • 516
Djangonaut
  • 5,511
  • 7
  • 40
  • 53
  • 2
    No need for a lambda : `await sync_to_async(list)(User.objects.all())` –  Jun 23 '20 at 12:09

2 Answers2

16

There is a common GOTCHA: Django querysets are lazy evaluated (database query happens only when you start iterating):

so instead - use evaluation (with list):

from asgiref.sync import sync_to_async

async def myview(request):
    users = await sync_to_async(list)(User.objects.all())
4

From Django 4.1, async for is supported on all QuerySets:

async def myview(request):
    users = [user async for user in User.objects.all()]
        

more info: link

Masoud Gheisari
  • 949
  • 1
  • 9
  • 21