← Назад к вопросам

Какие есть проблемы у Django, с которыми можно столкнутся при реализации проектов?

2.0 Middle🔥 121 комментариев
#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Проблемы 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 версию
Какие есть проблемы у Django, с которыми можно столкнутся при реализации проектов? | PrepBro