Optimizing Django Performance: A Complete Checklist
admin
November 22, 2025
•
3 min read
222 views
Speed up your Django application with these proven optimization techniques covering database, caching, and frontend.
Optimizing Django Performance
Slow applications frustrate users and hurt your bottom line. Here's a comprehensive checklist to make your Django app faster.
Database Optimization
1. Use select_related and prefetch_related
The N+1 query problem is the most common performance killer.
# BAD: N+1 queries
for order in Order.objects.all():
print(order.user.email) # Query for each order!
# GOOD: Single query with JOIN
for order in Order.objects.select_related('user'):
print(order.user.email)
# For many-to-many relationships
products = Product.objects.prefetch_related('categories', 'tags')
2. Add Database Indexes
class Product(models.Model):
name = models.CharField(max_length=200, db_index=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
created_at = models.DateTimeField(db_index=True)
class Meta:
indexes = [
models.Index(fields=['category', 'created_at']),
models.Index(fields=['name', 'is_active']),
]
3. Use only() and defer()
Fetch only the fields you need:
# Fetch only specific fields
products = Product.objects.only('id', 'name', 'price')
# Exclude heavy fields
products = Product.objects.defer('description', 'long_content')
4. Bulk Operations
# BAD: Individual inserts
for item in items:
Product.objects.create(**item)
# GOOD: Bulk insert
Product.objects.bulk_create([
Product(**item) for item in items
])
# GOOD: Bulk update
Product.objects.filter(category='old').update(category='new')
Caching Strategies
1. Database Query Caching
from django.core.cache import cache
def get_featured_products():
key = 'featured_products'
products = cache.get(key)
if products is None:
products = list(Product.objects.filter(
is_featured=True
).select_related('category')[:10])
cache.set(key, products, 60 * 15) # 15 minutes
return products
2. View Caching
from django.views.decorators.cache import cache_page
@cache_page(60 * 15) # 15 minutes
def product_list(request):
products = Product.objects.all()
return render(request, 'products.html', {'products': products})
3. Template Fragment Caching
{% load cache %}
{% cache 500 sidebar request.user.id %}
<!-- Expensive sidebar content -->
{% endcache %}
4. Redis Configuration
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'
Query Analysis
Django Debug Toolbar
Install and use it in development:
INSTALLED_APPS = [
...
'debug_toolbar',
]
MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware',
...
]
Query Logging
LOGGING = {
'version': 1,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'level': 'DEBUG',
'handlers': ['console'],
},
},
}
Frontend Optimization
1. Static File Compression
# settings.py
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
2. Image Optimization
from PIL import Image
def optimize_image(image_path, max_size=(800, 800), quality=85):
img = Image.open(image_path)
img.thumbnail(max_size, Image.LANCZOS)
img.save(image_path, optimize=True, quality=quality)
3. Lazy Loading
<img src="placeholder.jpg"
data-src="actual-image.jpg"
loading="lazy"
alt="Product">
Application Settings
1. Persistent Database Connections
DATABASES = {
'default': {
...
'CONN_MAX_AGE': 600, # 10 minutes
}
}
2. Session Backend
# Use cache-based sessions
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
3. Disable Debug in Production
DEBUG = False
Async Views (Django 4.0+)
async def async_product_list(request):
products = await sync_to_async(list)(
Product.objects.filter(is_active=True)[:20]
)
return render(request, 'products.html', {'products': products})
Performance Checklist
Database
- [ ] Add indexes to frequently queried fields
- [ ] Use select_related/prefetch_related
- [ ] Avoid N+1 queries
- [ ] Use bulk operations
- [ ] Enable connection pooling
Caching
- [ ] Cache expensive queries
- [ ] Use Redis for session storage
- [ ] Implement template fragment caching
- [ ] Set appropriate cache timeouts
Frontend
- [ ] Minify CSS/JS
- [ ] Optimize images
- [ ] Use CDN for static files
- [ ] Enable browser caching
- [ ] Lazy load images
Infrastructure
- [ ] Use production-grade server (Gunicorn)
- [ ] Enable gzip compression
- [ ] Use connection pooling (PgBouncer)
- [ ] Monitor with APM tools
Measuring Performance
Tools to use:
- Django Debug Toolbar: Development queries
- New Relic / Datadog: Production monitoring
- Lighthouse: Frontend performance
- Apache Bench: Load testing
# Load test with Apache Bench
ab -n 1000 -c 100 http://localhost:8000/products/
Conclusion
Performance optimization is iterative. Measure first, optimize the bottlenecks, and measure again. Don't optimize prematurely—focus on real problems.
Need performance-optimized templates? Check our marketplace!