Performance Optimization
Learn techniques to optimize Django applications for better performance in production. This is a foundational concept in Python web development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world Python/Django experience. Take your time with each section and practice the examples
Optimizing Django Applications
Performance optimization is crucial for production applications. Django provides many tools and techniques to improve application performance.. This is an essential concept that every Python/Django developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
Performance Techniques
# Database Optimization
# Use select_related for ForeignKey
posts = Post.objects.select_related('author', 'category').all()
# Use prefetch_related for ManyToMany
articles = Article.objects.prefetch_related('tags').all()
# Use only() to limit fields
posts = Post.objects.only('title', 'created_date').all()
# Use defer() to exclude fields
posts = Post.objects.defer('content').all()
# Database indexing
class Post(models.Model):
title = models.CharField(max_length=200, db_index=True)
created_date = models.DateTimeField(auto_now_add=True, db_index=True)
class Meta:
indexes = [
models.Index(fields=['author', 'created_date']),
models.Index(fields=['category', 'published_date']),
]
# Caching
from django.core.cache import cache
from django.views.decorators.cache import cache_page
# View-level caching
@cache_page(60 * 15) # Cache for 15 minutes
def expensive_view(request):
# Expensive computation
return render(request, 'template.html')
# Template fragment caching
{% load cache %}
{% cache 500 sidebar request.user.username %}
<!-- Expensive sidebar content -->
{% endcache %}
# Low-level caching
def get_user_posts(user_id):
cache_key = f'user_posts_{user_id}'
posts = cache.get(cache_key)
if posts is None:
posts = Post.objects.filter(author_id=user_id)
cache.set(cache_key, posts, 300) # Cache for 5 minutes
return posts
# Database connection optimization
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydb',
'CONN_MAX_AGE': 60, # Keep connections alive for 60 seconds
'OPTIONS': {
'MAX_CONNS': 20, # Maximum connections
}
}
}
# Static files optimization
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
# Template optimization
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'loaders': [
('django.template.loaders.cached.Loader', [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
]),
],
},
},
]
# Middleware optimization
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # Serve static files
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# Query optimization
from django.db.models import Count, Prefetch
# Optimize complex queries
posts = Post.objects.select_related('author').prefetch_related(
Prefetch('comments', queryset=Comment.objects.select_related('author'))
).annotate(
comment_count=Count('comments')
)
# Use bulk operations
# Bulk create
Post.objects.bulk_create([
Post(title=f'Post {i}', content=f'Content {i}')
for i in range(1000)
])
# Bulk update
Post.objects.filter(is_featured=True).update(
featured_date=timezone.now()
)