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

Чем пользовался для оптимизации запросов в Django?

1.8 Middle🔥 151 комментариев
#Django#Базы данных (SQL)

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

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

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

Чем пользовался для оптимизации запросов в Django

Django предоставляет мощный набор инструментов для оптимизации запросов к БД. Это критически важно для производительности приложений.

1. select_related() — для ForeignKey и OneToOne

class Post(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey('User', on_delete=models.CASCADE)

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    user = models.ForeignKey('User', on_delete=models.CASCADE)

# Проблема: N+1 SELECT
comments = Comment.objects.all()
for comment in comments:
    print(comment.post.title)  # Новый SELECT для каждого!

# Решение: select_related()
comments = Comment.objects.select_related('post', 'user').all()
for comment in comments:
    print(comment.post.title)  # Уже в памяти!

2. prefetch_related() — для ManyToMany и reverse ForeignKey

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=200)
    authors = models.ManyToManyField(Author)

# Проблема: N+1 SELECT
books = Book.objects.all()
for book in books:
    authors = book.authors.all()  # Новый SELECT!

# Решение: prefetch_related()
books = Book.objects.prefetch_related('authors').all()
for book in books:
    authors = book.authors.all()  # Кешировано!

3. only() и defer() — выбрать нужные колонки

# Загружаем ВСЕ
users = User.objects.all()

# Только нужное
users = User.objects.only('id', 'username', 'email')

# Исключаем ненужное
users = User.objects.defer('bio', 'large_text')

4. Annotate() — агрегация в БД

from django.db.models import Count, Sum, Avg

# Проблема: отдельный COUNT для каждого юзера
for user in User.objects.all():
    post_count = user.posts.count()

# Решение: аннотация
users = User.objects.annotate(
    post_count=Count('posts'),
    total_views=Sum('posts__views'),
    avg_likes=Avg('posts__likes')
).filter(post_count__gte=5)

5. values() и values_list()

# Полные объекты
users = User.objects.all()

# Словари
users = User.objects.values('id', 'username', 'email')

# Кортежи
users = User.objects.values_list('id', 'username')
for user_id, username in users:
    print(f"{user_id}: {username}")

6. exists() вместо count()

# Медленно: считает ВСЕ
if User.objects.filter(email='test@example.com').count() > 0:
    ...

# Быстро: останавливается после первой
if User.objects.filter(email='test@example.com').exists():
    ...

7. bulk_create() и bulk_update()

# Медленно: 1000 INSERT запросов
users = [User(username=f'user{i}') for i in range(1000)]
for user in users:
    user.save()

# Быстро: несколько запросов
User.objects.bulk_create(users, batch_size=500)

# Обновление
User.objects.bulk_update(users, fields=['last_login'], batch_size=500)

8. Django Debug Toolbar

# settings.py
INSTALLED_APPS = ['debug_toolbar', ...]
MIDDLEWARE = ['debug_toolbar.middleware.DebugToolbarMiddleware', ...]
INTERNAL_IPS = ['127.0.0.1']

# urls.py
if DEBUG:
    import debug_toolbar
    urlpatterns += [path('__debug__/', include(debug_toolbar.urls))]

# В браузере видите все SQL запросы и время выполнения

9. QuerySet.explain()

users = User.objects.all()
print(users.query.explain(verbose=True))
# Показывает EXPLAIN ANALYZE из БД

10. Полный пример оптимизации

from django.db.models import Count, Prefetch

class BlogListView(ListView):
    model = Post
    
    def get_queryset(self):
        return Post.objects.select_related(
            'author',
            'category'
        ).prefetch_related(
            'tags',
            Prefetch('comments', queryset=Comment.objects.select_related('author'))
        ).only(
            'id', 'title', 'published_at',
            'author__id', 'author__username',
            'category__name'
        ).annotate(
            comment_count=Count('comments'),
            tag_count=Count('tags')
        ).filter(
            published=True,
            comment_count__gte=1
        ).order_by('-published_at')

Чеклист оптимизации

  1. select_related() для ForeignKey / OneToOne
  2. prefetch_related() для ManyToMany / reverse FK
  3. only() / defer() для нужных колонок
  4. annotate() для агрегации в БД
  5. values() / values_list() для словарей/кортежей
  6. exists() вместо count() для проверки
  7. bulk_create() / bulk_update() для пакетов
  8. Debug Toolbar для профилирования
  9. explain() для анализа плана
  10. Тестировать с реальным объёмом данных!

Оптимизация запросов в Django — систематический подход, начиная с профилирования и заканчивая применением инструментов кеширования.