← Назад к вопросам
Как реализовать асинхронность в Django?
2.0 Middle🔥 181 комментариев
#Django#Асинхронность и многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Асинхронность в Django
Джанго исторически был синхронным фреймворком, но начиная с версии 3.1 поддерживает асинхронный код. Это позволяет обрабатывать больше одновременных подключений без использования многопроцессности.
1. Асинхронные views (Django 3.1+)
Базовый пример
# views.py
import asyncio
from django.http import JsonResponse
# Просто добавь async перед def
async def get_user_async(request, user_id):
# Это автоматически запустится в event loop
user = await fetch_user_from_db(user_id)
return JsonResponse({"id": user.id, "name": user.name})
# Маршрут
from django.urls import path
urlpatterns = [
path('users/<int:user_id>/', get_user_async), # async view работает!
]
Что внутри происходит
Когда Django видит async view:
1. Запрос приходит
2. Django создаёт event loop (если его нет)
3. Запускает async view в этом loop
4. Ждёт завершения
5. Отправляет ответ
2. Асинхронные запросы в БД
Problem: Django ORM не async по умолчанию
# ❌ НЕПРАВИЛЬНО: ORM операции блокируют
async def get_user(user_id):
user = User.objects.get(id=user_id) # БЛОКИРУЕТ!
return user
# Это синхронная операция, она заморозит весь event loop!
Решение 1: sync_to_async
from django.utils.decorators import sync_to_async
from django.db.models import F
# Оборни синхронный код в async
@sync_to_async
def get_user_from_db(user_id):
return User.objects.get(id=user_id)
async def user_view(request, user_id):
user = await get_user_from_db(user_id) # Теперь async!
return JsonResponse({"name": user.name})
Решение 2: Асинхронный ORM (asyncpg, databases)
Для более сложных случаев используй асинхронный драйвер:
pip install asyncpg databases
import databases
from typing import List
# Инициализация
database = databases.Database(
"postgresql+asyncpg://user:pass@localhost/db"
)
# Асинхронная функция для запросов
async def get_users() -> List[dict]:
query = "SELECT id, name, email FROM users"
return await database.fetch_all(query)
# View
async def users_list(request):
users = await get_users()
return JsonResponse({"users": users})
3. Асинхронные функции-помощники
Пример: HTTP запрос
import aiohttp
import asyncio
from django.http import JsonResponse
async def fetch_external_api(url: str):
"""Асинхронный запрос к внешнему API"""
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
async def dashboard_view(request):
# Параллельно запрашиваем несколько API
github_data, api_data = await asyncio.gather(
fetch_external_api("https://api.github.com/users/python"),
fetch_external_api("https://api.example.com/data")
)
return JsonResponse({
"github": github_data,
"api": api_data
})
Асинхронные tasks
import asyncio
from django.http import JsonResponse
async def send_emails_async(user_ids: list):
"""Отправляем письма параллельно"""
tasks = []
for user_id in user_ids:
tasks.append(send_email_to_user(user_id))
results = await asyncio.gather(*tasks)
return results
async def notify_users(request):
user_ids = [1, 2, 3, 4, 5]
await send_emails_async(user_ids) # Параллельно!
return JsonResponse({"status": "emails sent"})
4. Асинхронные Middleware
# middleware.py
import time
from django.utils.decorators import sync_and_async_middleware
@sync_and_async_middleware
def timing_middleware(get_response):
if asyncio.iscoroutinefunction(get_response):
async def middleware(request):
start = time.time()
response = await get_response(request)
response["X-Process-Time"] = time.time() - start
return response
else:
def middleware(request):
start = time.time()
response = get_response(request)
response["X-Process-Time"] = time.time() - start
return response
return middleware
5. Асинхронные сигналы и обработчики
from django.dispatch import receiver
from django.core.signals import request_started
from django.utils.decorators import sync_and_async_middleware
import asyncio
# Асинхронный обработчик сигнала
@receiver(request_started, dispatch_uid='async_signal')
async def handle_request_started(sender, **kwargs):
# Выполняем асинхронный код
await log_request_async(kwargs)
6. Использование Celery для async tasks
Для тяжёлых операций лучше использовать task queue:
pip install celery redis
# celery.py
from celery import Celery
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()
app = Celery('myproject')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
# tasks.py
from celery import shared_task
import time
@shared_task
def send_email_task(user_id):
"""Задача запущена асинхронно в Celery worker"""
user = User.objects.get(id=user_id)
send_email(user.email)
return f"Email sent to {user.email}"
# views.py
from django.http import JsonResponse
from .tasks import send_email_task
def send_notification(request, user_id):
# Запускаем задачу в фоне
task = send_email_task.delay(user_id)
return JsonResponse({"task_id": task.id})
def get_task_status(request, task_id):
from celery.result import AsyncResult
task = AsyncResult(task_id)
return JsonResponse({"status": task.status, "result": task.result})
7. Асинхронный WebSocket (Django Channels)
Для real-time функционала используй Django Channels:
pip install channels channels-redis
# settings.py
INSTALLED_APPS = [
'daphne', # ASGI сервер вместо WSGI
'channels',
# остальные приложения
]
ASGI_APPLICATION = 'myproject.asgi.application'
# asgi.py
import os
from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from django.urls import path
from . import consumers
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket': AuthMiddlewareStack(
URLRouter([
path('ws/chat/<room_name>/', consumers.ChatConsumer.as_asgi()),
])
),
})
# consumers.py
from channels.generic.websocket import AsyncWebsocketConsumer
import json
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = f'chat_{self.room_name}'
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def receive(self, text_data):
data = json.loads(text_data)
message = data['message']
# Отправляем всем в группе
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
async def chat_message(self, event):
message = event['message']
await self.send(text_data=json.dumps({
'message': message
}))
8. Асинхронная миграция с ASGI
# Используй Daphne или Hypercorn вместо Gunicorn
pip install daphne
# Запуск
daphne -b 0.0.0.0 -p 8000 myproject.asgi:application
# Или с несколькими воркерами
daphne -b 0.0.0.0 -p 8000 -w 4 myproject.asgi:application
9. Конфигурация для production
# settings.py
# Для ASGI сервера (async views)
ASGI_APPLICATION = 'myproject.asgi.application'
# Если используешь Celery для async tasks
CELERY_BROKER_URL = 'redis://localhost:6379'
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
# Database оптимизация
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'ATOMIC_REQUESTS': False, # Отключи для async
'CONN_MAX_AGE': 0, # Не переиспользуй соединения
}
}
# Асинхронные фичи
DATABASES['default']['OPTIONS'] = {
'connect_timeout': 10,
}
10. Best Practices
✅ Делай так:
# 1. Используй async для I/O операций
async def fetch_data(url):
async with aiohttp.ClientSession() as session:
return await session.get(url)
# 2. Используй sync_to_async для ORM
get_user = sync_to_async(User.objects.get)
# 3. Параллели операции с asyncio.gather
results = await asyncio.gather(task1(), task2(), task3())
# 4. Используй Celery для long-running tasks
@shared_task
def long_operation():
...
❌ Не делай так:
# 1. Не блокируй event loop
async def view(request):
time.sleep(5) # ПЛОХО!
return response
# 2. Не мешай sync и async без adapter
async def view(request):
user = User.objects.get(id=1) # Заморозит!
# 3. Не запускай async в синхронном коде
# без asyncio.run()
Заключение
Асинхронность в Django — это evolution, не revolution. Варианты:
- async views — для простых I/O операций
- sync_to_async — обёртка для ORM
- Celery — для тяжелых фоновых задач
- Channels — для WebSocket и real-time
- ASGI — инфраструктура для всего выше
Выбирай инструмент в зависимости от задачи!