Back to Rules
Django87% popularity

Django QuerySet Optimization

Use select_related, prefetch_related, and only() to minimize database queries.

Aymeric AugustinUpdated Feb 25, 2024

Overview

Django's ORM is powerful but can hide performance pitfalls through abstraction. Understanding QuerySet optimization techniques is essential for building performant Django applications, as the ORM's convenience features can easily generate N+1 query problems that multiply database load. select_related creates an SQL JOIN for the specified foreign key relationships, fetching related objects in a single query. This is appropriate for foreign keys and one-to-one relationships where you always need the related object. Using it on the wrong relationships (like many-to-many or reverse foreign keys) creates large joins that may actually hurt performance. prefetch_related executes a separate query for each relationship and joins them in Python, making it ideal for many-to-many and reverse foreign key relationships. For example, prefetching tags for articles executes one query for articles and another for all tags, then matches them in Python rather than creating a large Cartesian product in SQL. The only() method limits the fields fetched from the database, which can significantly reduce memory usage and transfer time for models with many fields. defer() is the inverse—it excludes specified fields, useful for fields that are expensive to render like TEXT or JSON columns. The values() and values_list() methods return dictionaries or tuples instead of full model instances, further reducing overhead. Raw SQL with extra() and raw() should be considered for complex queries where the ORM generates suboptimal SQL. The explain() method helps identify problem queries by showing the query plan. For truly complex operations, stored procedures or raw SQL with proper parameterization may be necessary despite the ORM's capabilities.

Code Example

.djangorules
from django.db.models import Prefetch, Count, Q
from django.shortcuts import render
from .models import Author, Book, Publisher

# Problematic: N+1 queries
def authors_with_books_slow(request):
    authors = Author.objects.all()
    for author in authors:
        # This causes a query for each author!
        print(author.books.all())
    return render(request, 'authors.html', {'authors': authors})

# Optimized with select_related
def authors_list_optimized(request):
    authors = Author.objects.select_related('publisher').all()

    # Single query with JOIN for publisher
    # books accessed without additional queries
    return render(request, 'authors.html', {'authors': authors})

# Prefetching for reverse relationships
def book_list_with_reviews(request):
    books = Book.objects.select_related(
        'author',
        'publisher'
    ).prefetch_related(
        'reviews',
        'tags'
    ).annotate(
        review_count=Count('reviews'),
        avg_rating=Avg('reviews__rating')
    ).order_by('-pub_date')[:20]

    # Only 3 queries total regardless of number of books
    return render(request, 'books.html', {'books': books})

# Complex prefetch with filtered queryset
def publisher_detail(request, pk):
    publisher = Publisher.objects.prefetch_related(
        Prefetch(
            'books',
            queryset=Book.objects.filter(is_active=True)
                         .select_related('author')
                         .only('title', 'pub_date', 'author__name')
        )
    ).get(pk=pk)

    return render(request, 'publisher.html', {'publisher': publisher})

# Using values() for read-only data
def author_statistics(request):
    stats = Author.objects.values('specialty').annotate(
        author_count=Count('id'),
        total_books=Count('books')
    ).order_by('-total_books')

    # Returns dicts instead of model instances - much faster
    return render(request, 'stats.html', {'stats': stats})

More Django Rules

DJANGO
89%

Django REST Framework Serializer Validation

Implement multi-layer validation in DRF serializers for robust API input handling and security.

djangorest-frameworkvalidation
from rest_framework import serializers
from django.contrib.auth import get_user_model
from django.utils import timezone
from .models import Project, T...
Mar 5, 2024by Tom Christie
View Rule
DJANGO
91%

Django Security Best Practices

Implement comprehensive security measures including CSRF, XSS prevention, and SQL injection protection.

djangosecuritycsrf
from django.http import HttpResponse, HttpResponseForbidden
from django.views.decorators.http import require_http_methods
from django.views.decorators...
Mar 2, 2024by Django Software Foundation
View Rule
DJANGO
89%

Django REST Framework Permissions

Implement granular permission systems with DRF permission classes and custom permission logic.

djangorest-frameworkpermissions
from rest_framework import permissions
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.gener...
Mar 25, 2024by Tom Christie
View Rule