Ответ
Начиная с Django 3.1, можно создавать асинхронные представления (views), используя синтаксис async def. Это позволяет эффективно обрабатывать I/O-bound операции (например, HTTP-запросы к внешним API, работа с WebSocket) без блокировки потока.
Пример простого асинхронного представления:
import asyncio
from django.http import JsonResponse
async def my_async_view(request):
# Имитация неблокирующей операции, например, запроса к API
await asyncio.sleep(1)
return JsonResponse({'status': 'ok', 'message': 'Completed async task'})
Ограничения и работа с ORM
Основное ограничение заключается в том, что ORM Django до версии 4.1 был полностью синхронным. Вызов синхронного кода ORM (например, User.objects.all()) внутри async def заблокирует event loop.
Для решения этой проблемы используется адаптер asgiref.sync.sync_to_async.
Пример асинхронного view с синхронным вызовом ORM:
from asgiref.sync import sync_to_async
from django.contrib.auth.models import User
from django.http import JsonResponse
# Оборачиваем синхронный вызов ORM в асинхронную функцию
@sync_to_async
def get_user_count():
return User.objects.count()
async def user_count_view(request):
# Асинхронно ожидаем результат выполнения синхронного кода
count = await get_user_count()
return JsonResponse({'user_count': count})
Примечание: Начиная с Django 4.1, ORM получил частичную нативную поддержку асинхронных операций (например, aget, acreate, acount), что упрощает написание такого кода.
Ответ 18+ 🔞
Да ты посмотри, что эти Django-разработчики вытворяют! С версии 3.1, блядь, они нам подсунули асинхронные вьюхи через async def. Ну, в принципе, логично — если у тебя там запросы к каким-нибудь внешним API, которые тормозят как черепаха в патруле, или WebSocket'ы, то это самое оно. Не будет твой сервер, сука, тупить впустую, пока ждёт ответа.
Вот, смотри, элементарный пример:
import asyncio
from django.http import JsonResponse
async def my_async_view(request):
# Представь, что тут мы ждём ответ от какого-нибудь медленного сервиса
await asyncio.sleep(1)
return JsonResponse({'status': 'ok', 'message': 'Completed async task'})
Но есть, конечно, подводный ебучий камень
Вся соль в ORM, ёпта! До версии 4.1 эта штука была синхронной в корне. Если ты внутри своего красивого async def попробуешь сделать User.objects.all() — всё, приехали. Event loop встанет колом, как будто ему в рот чих-пых.
Что делать? Обёртывать, блядь! Есть такой спасательный круг — asgiref.sync.sync_to_async. Им и пользуемся.
Смотри, как это выглядит в деле:
from asgiref.sync import sync_to_async
from django.contrib.auth.models import User
from django.http import JsonResponse
# Берём синхронную функцию и делаем из неё асинхронную обёртку
@sync_to_async
def get_user_count():
return User.objects.count()
async def user_count_view(request):
# Теперь можно спокойно ждать
count = await get_user_count()
return JsonResponse({'user_count': count})
Важное замечание, чтобы не облажаться: Начиная с Django 4.1, там уже понапихали нативных асинхронных методов в ORM — aget, acreate, acount и прочие. Так что теперь можно не городить эти обёртки, а писать почти как обычно, только с приставкой 'a'. Но если ты, как и я, ещё сидишь на старом проекте — учись оборачивать, хитрая жопа.