Django QuerySet Optimization
Use select_related, prefetch_related, and only() to minimize database queries.
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
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 REST Framework Serializer Validation
Implement multi-layer validation in DRF serializers for robust API input handling and security.
from rest_framework import serializers
from django.contrib.auth import get_user_model
from django.utils import timezone
from .models import Project, T...Django Security Best Practices
Implement comprehensive security measures including CSRF, XSS prevention, and SQL injection protection.
from django.http import HttpResponse, HttpResponseForbidden
from django.views.decorators.http import require_http_methods
from django.views.decorators...Django REST Framework Permissions
Implement granular permission systems with DRF permission classes and custom permission logic.
from rest_framework import permissions
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.gener...