Какие есть проблемы у Django, с которыми можно столкнутся при реализации проектов?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Проблемы Django при реализации проектов
Django — отличный фреймворк, но он имеет недостатки, которые проявляются при масштабировании и сложных проектах.
1. N+1 Query Problem
Джанго выполняет отдельный SQL запрос для каждого объекта связи:
# ПЛОХО: N+1 запросов
users = User.objects.all()
for user in users: # 1 запрос
print(user.profile.bio) # N запросов (по одному на пользователя)
# Если 1000 пользователей = 1001 запрос!
Решение:
# ХОРОШО: 1 запрос с JOIN
users = User.objects.select_related('profile').all()
# Для reverse relations (One-to-Many)
users = User.objects.prefetch_related('posts').all()
# Комбинированное
users = User.objects.select_related('profile').prefetch_related('posts')
2. ORM медленнее чем raw SQL
ORM добавляет overhead:
# ORM (медленнее)
users = User.objects.filter(
profile__age__gte=18,
posts__published=True
).distinct().values('id', 'email')
# Raw SQL (быстрее)
users = User.objects.raw("""
SELECT DISTINCT u.id, u.email
FROM auth_user u
JOIN auth_profile p ON u.id = p.user_id
JOIN blog_post bp ON u.id = bp.user_id
WHERE p.age >= 18 AND bp.published = true
""")
Проблема: сложные запросы становятся неэффективными через ORM.
3. Миграции и развёртывание
# Проблема: миграция может сломать production
# Добавляем новое поле БЕЗ default
class User(models.Model):
email = models.EmailField() # Было
username = models.CharField(max_length=100) # Новое поле
# Миграция падает для старых записей (нет значения для username)
Решение: используй null=True временно, потом заполни, потом убери null=True.
# Шаг 1
username = models.CharField(max_length=100, null=True, blank=True)
# Шаг 2: Data migration для заполнения
def populate_usernames(apps, schema_editor):
User = apps.get_model('auth', 'User')
for user in User.objects.all():
user.username = f"user_{user.id}"
user.save()
# Шаг 3
username = models.CharField(max_length=100, null=False)
4. Signal Hell
Signals в Django могут создавать каскадные эффекты:
# Проблема: сложная цепочка
from django.db.models.signals import post_save
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
# Это срабатывает после каждого User.save()
# Может вызвать другой signal
Profile.objects.create(user=instance)
@receiver(post_save, sender=Profile)
def send_welcome_email(sender, instance, created, **kwargs):
if created:
# Отправляем email
send_email.delay(instance.user.email)
# Вызывает Celery задачу
# Которая может вызвать ещё signals
Проблема: сложно отследить что происходит.
Решение: используй Use Cases вместо Signals:
# Чище
class CreateUserUseCase:
def execute(self, email, password):
user = User.objects.create_user(email=email, password=password)
profile = Profile.objects.create(user=user)
send_welcome_email(email)
return user
5. Django ORM слабо с JSON
# У тебя есть JSON поле
class Article(models.Model):
metadata = models.JSONField()
# И ты хочешь филтровать
articles = Article.objects.filter(
metadata__author__name='John' # Может не работать
)
# Raw SQL работает лучше
from django.db.models.functions import Cast
articles = Article.objects.annotate(
author=Cast('metadata__author__name', CharField())
).filter(author='John')
6. Middleware и контроль порядка выполнения
Порядок middleware критичен, но его легко нарушить:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'myapp.middleware.AuthMiddleware', # Должна быть после Session!
'django.middleware.common.CommonMiddleware',
]
# Если порядок неправильный, auth может не работать
7. Кеширование сложное и неintutive
# Проблема: кеш может быть несинхронизирован с БД
from django.views.decorators.cache import cache_page
@cache_page(60) # 1 минуту
def get_user(request, user_id):
user = User.objects.get(id=user_id)
# Если user обновится, кеш останется старым!
return render(request, 'user.html', {'user': user})
# Нужно вручную инвалидировать
from django.core.cache import cache
cache.delete(f'user_{user_id}')
8. Отсутствие встроенного API
Django не имеет встроенного REST API:
# Нужно добавлять Django REST framework отдельно
pip install djangorestframework
# Конфиг становится громозким
INSTALLED_APPS = [
'rest_framework',
'rest_framework.authtoken',
'corsheaders',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
9. Масштабирование на горизонте
# Django монолит сложно разбить
# Если нужны микросервисы, теряешь преимущества Django
# Лучше использовать FastAPI
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return {"id": user_id}
10. Стандартная админка неэффективна на большие данные
# Проблема: админка грузит ВСЕ записи
class ArticleAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'created_at')
# Если 100k статей, админ замирает
# Решение: используй raw_id_fields и фильтры
class ArticleAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'created_at')
raw_id_fields = ('author',)
list_filter = ('created_at', 'status')
search_fields = ('title', 'content')
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('author').prefetch_related('tags')
11. Асинхронность (async/await)
Django 3.1+ поддерживает async, но это непрозрачно:
# async view
async def get_user(request, user_id):
user = await User.objects.aget(id=user_id) # aget, не get!
return JsonResponse({"user": user})
# Проблема: нужно переписать весь код на async
# ORM работает медленнее в async
12. Зависимость от single database
Динамическое переключение БД сложное:
# Если нужны несколько БД
DATABASES = {
'default': {...},
'replica': {...},
}
# Нужно вручную управлять
User.objects.using('replica').filter(id=1)
Итоговые рекомендации
Используй Django когда:
- Простой CRUD проект
- Нужна админка
- Небольшая команда
- Приоритет скорость разработки
Переходи на FastAPI когда:
- Нужен микросервис
- Высокие требования по производительности
- Асинхронные операции
- REST API
Итоговый чеклист:
- Используй select_related и prefetch_related
- Кешируй правильно (инвалидируй при обновлениях)
- Логируй все медленные запросы (Django Debug Toolbar)
- Тестируй миграции перед production
- Избегай signals, используй use cases
- Мониторь production (NewRelic, Sentry)
- Регулярно обновляй Django версию