Async Views & ASGI
An async view is a view defined with async def that can await coroutines, letting the server do other work while it waits on slow input or output such as a database query or an external API call.
Learn Async Views & ASGI in our free Django course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Django course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll write async def views, see exactly when async helps by running calls concurrently with asyncio.gather, bridge sync and async with sync_to_async, touch the async ORM, and run the project under an ASGI server.
An async view looks almost identical to a normal one — you just write async def and use await for any coroutine it calls. Django recognizes the coroutine and runs it on the event loop. The win is that while the view is await ing slow input or output, the server isn't blocked and can make progress on other requests.
Async pays off when a view makes several independent I/O calls . With asyncio.gather you launch them all at once and await them together, so they overlap instead of running one after another. Three 100ms calls finish in about 100ms total. For CPU-heavy work or a single quick query, async gives little or no benefit.
Real apps mix worlds. sync_to_async wraps blocking code so an async view can await it; async_to_sync runs a coroutine from sync code. Since Django 4.1 the ORM has async methods — the same queries with an a prefix, like afirst , acreate , and async for . To run async views with full concurrency, serve the project through asgi.py with an ASGI server like Uvicorn or Daphne.
Replace the blank with asyncio.gather(...) so the two awaited tasks run concurrently and return a list of results.
You called the sync ORM directly inside async def .
✅ Fix: use the async methods ( afirst , acreate , async for ) or wrap in sync_to_async .
You awaited calls one at a time, so they ran sequentially.
✅ Fix: launch independent calls together with asyncio.gather(...) .
You called an async function without await , so it never ran.
✅ Fix: await the coroutine, or pass it to gather .
Write an async view that fans out to three services with gather , combines the results, and shows that the three 100ms calls finish in about 100ms total.
Lesson complete — you can write concurrent views!
You wrote async def views, saw exactly when async helps by overlapping I/O with asyncio.gather, bridged worlds with sync_to_async, used the async ORM's a-prefixed methods, and learned to serve the project under an ASGI server.
🚀 Up next: Real-Time with Django Channels — add WebSockets, consumers, and broadcast over the ASGI layer.
Practice quiz
How do you define an async view in Django?
- def view(request): with @async
- async view(request):
- view = async(request)
- async def view(request):
Answer: async def view(request):. An async view is simply written with async def and can await coroutines.
What does asyncio.gather let you do?
- Run several awaitables concurrently
- Block the event loop
- Cache responses
- Define a model
Answer: Run several awaitables concurrently. gather launches awaitables together so independent I/O calls overlap.
When does async give the biggest speedup?
- Heavy CPU computation
- A single quick query
- Several independent I/O calls run concurrently
- Rendering a static page
Answer: Several independent I/O calls run concurrently. Async helps most when overlapping multiple independent I/O-bound calls.
What does sync_to_async do?
- Speeds up CPU work
- Wraps blocking code so an async view can await it
- Converts a model to JSON
- Starts an ASGI server
Answer: Wraps blocking code so an async view can await it. sync_to_async wraps a blocking function so it can be awaited without freezing the loop.
Which is a correct async ORM method added in Django 4.1?
- Post.objects.first_async()
- Post.objects.get_async()
- Post.objects.async_first()
- Post.objects.afirst()
Answer: Post.objects.afirst(). The async ORM mirrors sync methods with an 'a' prefix, e.g. afirst, acreate.
What error can the sync ORM raise inside an async view?
- SynchronousOnlyOperation
- AsyncRequiredError
- EventLoopError
- BlockingIOError
Answer: SynchronousOnlyOperation. Calling the sync ORM directly in async def can raise SynchronousOnlyOperation.
Which protocol replaces WSGI for async Django?
- FastCGI
- ASGI
- HTTP/3
- gRPC
Answer: ASGI. ASGI is the async successor to WSGI and supports long-lived connections.
Which command serves the project under an ASGI server?
- python manage.py runwsgi
- gunicorn myproject.wsgi
- uvicorn myproject.asgi:application
- python manage.py asgi
Answer: uvicorn myproject.asgi:application. An ASGI server like Uvicorn or Daphne serves the asgi:application callable.
Why might an async view be no faster than a sync one?
- You awaited calls one at a time instead of using gather
- You used JsonResponse
- You forgot to import asyncio
- You used too few URLs
Answer: You awaited calls one at a time instead of using gather. Awaiting sequentially runs calls one after another; use gather to overlap them.
What causes a 'coroutine was never awaited' warning?
- Using gather
- Defining async def
- Serving under ASGI
- Calling an async function without await
Answer: Calling an async function without await. Calling a coroutine without await (or gather) means it never runs.