Какие используешь библиотеки для оптимизации в Django?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие используешь библиотеки для оптимизации в Django?
Оптимизация Django-приложения — это критически важный аспект production-разработки. Вот библиотеки, которые я использую регулярно.
1. Django Debug Toolbar
Для чего: Анализ SQL запросов, профилирование, отладка.
# settings.py
INSTALLED_APPS = [
'debug_toolbar',
# ...
]
MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware',
# ...
]
INTERNAL_IPS = ['127.0.0.1']
# urls.py
if settings.DEBUG:
urlpatterns += [
path('__debug__/', include('debug_toolbar.urls')),
]
Что показывает:
- Количество SQL запросов
- Дублирующиеся запросы (N+1 проблема)
- Время выполнения
- Кэширование и middleware
2. Django Silk
Для чего: Profiling HTTP запросов в production (с осторожностью).
# settings.py
INSTALLED_APPS = [
'silk',
]
MIDDLEWARE = [
'silk.middleware.SilkyMiddleware',
]
SILKY_PYTHON_PROFILER = True
SILKY_IGNORE_PATTERNS = [r'^/static/', r'^/media/']
Возможности:
- История всех HTTP запросов
- Профилирование кода
- SQL запросы
- Визуальная диаграмма вызовов
3. django-extensions
Для чего: Утилиты для анализа и отладки.
# Использование
python manage.py shell_plus # Автоимпорт моделей
python manage.py runprofileserver # С профилированием
python manage.py show_urls # Список всех URL
python manage.py graph_models -a -o myapp.png # Граф моделей
# Для каждого эндпоинта показывает:
# - Время выполнения
# - CPU usage
# - Кумулятивное время
4. django-cachalot
Для чего: Автоматическое кэширование ORM запросов.
# settings.py
INSTALLED_APPS = [
'cachalot',
]
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
}
}
# Работает автоматически
from myapp.models import User
# Первый вызов — из БД
users = User.objects.all() # SQL запрос
# Второй вызов — из кэша
users = User.objects.all() # Из Redis, быстрее
# При изменении таблицы кэш инвалидируется автоматически
user = User.objects.create(name='John') # Кэш очищен
# Отключение кэша для критичных запросов
from cachalot.api import cachalot
with cachalot.disabled():
users = User.objects.all() # Всегда из БД
5. django-redis
Для чего: Интеграция Redis для кэширования и сессий.
# settings.py
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'CONNECTION_POOL_KWARGS': {
'max_connections': 50,
'retry_on_timeout': True,
},
'SOCKET_CONNECT_TIMEOUT': 5,
'SOCKET_TIMEOUT': 5,
}
}
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'
# Использование
from django.core.cache import cache
# Кэширование результата
user_data = cache.get('user_123')
if user_data is None:
user_data = User.objects.get(id=123)
cache.set('user_123', user_data, timeout=3600)
# Или декоратор
from django.views.decorators.cache import cache_page
@cache_page(60 * 15) # 15 минут
def expensive_view(request):
# Долгие вычисления
return render(request, 'template.html')
6. select_related и prefetch_related
Для чего: Решение N+1 проблемы.
from django.db.models import Prefetch
# ❌ Плохо — N+1 проблема
users = User.objects.all()
for user in users:
print(user.profile.bio) # На каждого user идёт отдельный запрос
# ✅ Хорошо — select_related для ForeignKey
users = User.objects.select_related('profile').all()
# SQL: SELECT * FROM user JOIN profile ON ...
# ✅ Для ManyToMany — prefetch_related
posts = Post.objects.prefetch_related('comments').all()
# SQL: SELECT * FROM post; SELECT * FROM comment WHERE post_id IN (...)
# Комбинирование
posts = Post.objects.select_related('author').prefetch_related('comments').all()
# Кастомный prefetch
from django.db.models import Prefetch
comments = Comment.objects.filter(approved=True)
posts = Post.objects.prefetch_related(
Prefetch('comments', queryset=comments)
).all()
7. django-rest-framework с оптимизацией
Для чего: Эффективные REST API.
from rest_framework import serializers, viewsets
from rest_framework.pagination import PageNumberPagination
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'name', 'email']
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
pagination_class = PageNumberPagination
def get_queryset(self):
# Оптимизированный queryset
queryset = super().get_queryset()
queryset = queryset.select_related('profile')
queryset = queryset.prefetch_related('posts')
# Фильтрация
if self.request.query_params.get('name'):
queryset = queryset.filter(
name__icontains=self.request.query_params.get('name')
)
return queryset
8. django-q
Для чего: Асинхронные задачи как альтернатива Celery.
# settings.py
INSTALLED_APPS = [
'django_q',
]
Q_CLUSTER = {
'name': 'myproject',
'workers': 4,
'timeout': 300,
'retry': 360,
'queue_limit': 50,
'orm': 'default',
}
from django_q.tasks import async_task, fetch
# Асинхронное выполнение
task_id = async_task('myapp.tasks.send_email',
to_email='user@example.com',
subject='Hello')
# Проверка статуса
result = fetch(task_id)
if result:
print(f"Результат: {result}")
else:
print("Задача ещё выполняется")
9. psycopg2 с connection pooling
Для чего: Эффективное подключение к БД.
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydb',
'USER': 'postgres',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '5432',
'CONN_MAX_AGE': 600, # Connection pooling
'OPTIONS': {
'connect_timeout': 10,
},
}
}
Или с pgbouncer (внешний pooler):
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydb',
'HOST': 'localhost',
'PORT': '6432', # pgbouncer port
}
}
10. django-queryset-sequence
Для чего: Объединение querysets из разных моделей.
from queryset_sequence import QuerySetSequence
users = User.objects.all()
admins = Admin.objects.all()
# Безопасное объединение
all_people = QuerySetSequence(users, admins)
for person in all_people:
print(person.name)
11. django-compression
Для чего: Сжатие static файлов.
# settings.py
INSTALLED_APPS = [
'compressor',
]
COMPRESSED_OFFLINE = True
COMPRESSED_CSS_FILTERS = [
'compressor.filters.css_default.CssAbsoluteFilter',
'compressor.filters.cssmin.rCSSMinFilter',
]
12. django-cors-headers (для API)
Для чего: Управление CORS.
INSTALLED_APPS = [
'corsheaders',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
]
CORS_ALLOWED_ORIGINS = [
'https://example.com',
'https://subdomain.example.com',
]
Практический пример оптимизации
# Плохая реализация
def get_user_posts(user_id):
user = User.objects.get(id=user_id) # Запрос 1
posts = user.posts.all() # Запрос 2
for post in posts: # N запросов
print(post.author.name)
for comment in post.comments.all(): # N запросов
print(comment.text)
# Оптимизированная версия
def get_user_posts(user_id):
return User.objects.filter(id=user_id).select_related(
'profile'
).prefetch_related(
Prefetch('posts',
queryset=Post.objects.select_related('author')
.prefetch_related('comments'))
)[0]
# Результат: 1 запрос вместо N+N²
Мой выбор для разных сценариев
- Отладка в development → Django Debug Toolbar
- Production monitoring → Django Silk (осторожно) или Sentry
- Кэширование ORM → django-cachalot
- Redis кэш → django-redis
- Асинхронные задачи → Celery или django-q
- Решение N+1 → select_related/prefetch_related
- REST API → DRF с оптимизацией querysets
- Connection pooling → CONN_MAX_AGE или pgbouncer
- Compression → django-compression
Ключевое правило: сначала профилируй, потом оптимизируй.