Caching in Django with Redis: A Step-by-Step Guide

Mehedi Khan
Django Unleashed
Published in
6 min readJun 11, 2024
Caching in Django with Redis: A Step-by-Step Guide

Caching in Django is an essential technique for improving the performance of web applications by storing frequently accessed data from memory, reducing the need for repeated database queries. Redis is a popular in-memory data structure store, often used as a cache in web applications due to its high performance and flexibility. This tutorial will guide you through setting up and using Redis as a cache backend for a Django project.

Prerequisites

Before we continue, make sure you have the following installed:

  • Python (preferably version 3.6 or higher)
  • Django (preferably version 3.0 or higher)
  • Redis server (installation instructions provided below)
  • Redis Python client (redis-py)

Step 1: Install Redis Server

On Ubuntu/Debian:

Use the following commands to install Redis:

sudo apt update
sudo apt install redis-server
sudo systemctl enable redis-server.service
sudo systemctl start redis-server.service
Install Redis Server: sudo apt update
Install Redis Server: sudo apt install redis-server
Install Redis Server: sudo systemctl enable redis-server.service
Check Redis Server: redis-server

On macOS:

You can use Homebrew to install Redis:

brew install redis
brew services start redis

On Windows:

You can download the Redis binaries from the Redis website or use the Windows Subsystem for Linux (WSL) to install Redis.

Using Docker:

docker run --name redis -d -p 6379:6379 redis

Step 2: Install Redis Python Client

Install the redis-py package using pip:

pip install redis

Step 3: Install Django-Redis

The django-redis package provides a Redis cache backend for Django. Install it using pip:

pip install django-redis

Step 4: Configure Redis in Django to Use caching

Open your Django project’s settings file (settings.py) and configure the cache settings to use Redis:

# settings.py

CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1', # Use the appropriate Redis server URL
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}

# Optional: This is to ensure Django sessions are stored in Redis
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'

Advanced Redis Cache Configuration

Connection Pooling

You can configure connection pooling for better performance:

# settings.py

CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'CONNECTION_POOL_KWARGS': {
'max_connections': 100,
'retry_on_timeout': True,
}
}
}
}

Using Sentinel

For high availability, you may use Redis Sentinel:

# settings.py

CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': [
'redis://127.0.0.1:26379/0',
'redis://127.0.0.1:26380/0',
'redis://127.0.0.1:26381/0',
],
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.SentinelClient',
'SENTINEL_KWARGS': {
'socket_timeout': 0.1,
},
}
}
}

Step 5: Basic Caching Operations

Using the Caching in Django Views

You can cache entire views using Django’s cache_page decorator:

from django.views.decorators.cache import cache_page
from django.http import HttpResponse

@cache_page(60 * 10) # view Cache for 10 minutes
def my_view(request):
# Your view logic
return HttpResponse("Hello, world. I am using djnago view cache.")

Low-Level Cache API

You may also use the low-level cache API for more granular control:

# For chack open your terminal
python manage.py shell
from django.core.cache import cache


# Set a value in the cache
cache.set('my_key', 'my_value', timeout=60 * 10) # Cache for 10 minutes

# Get a value from the cache
value = cache.get('my_key')
print(value) # Output: 'my_value'

# Delete a value from the cache
cache.delete('my_key')
Check caches in terminal
redis-cli monitor

For more advanced usage, you might want to use the low-level cache API provided by django-redis.

Working with Raw Redis Commands

from django_redis import get_redis_connection

redis_conn = get_redis_connection("default")
redis_conn.set('my_key', 'my_value')
value = redis_conn.get('my_key')

Caching with Querysets

You can cache the results of database queries to improve performance.

from django.core.cache import cache


def get_expensive_queryset():
queryset = cache.get('expensive_queryset')
if not queryset:
queryset = MyModel.objects.filter(...)
cache.set('expensive_queryset', queryset, timeout=60*15)
return queryset

Step 6: Advanced Usage

Fragment Caching

Sometimes, caching entire views could be better. You can cache parts of a template using the cache template tag.

{% load cache %}
{% cache 500 sidebar %}
... sidebar content ...
{% endcache %}

Per-View Caching with Varying on Headers

Django allows you to vary cache based on request headers, such as cookies or session data:

from django.views.decorators.vary import vary_on_cookie
from django.views.decorators.cache import cache_page

@vary_on_cookie
@cache_page(60 * 10)
def my_view(request):
# View logic goes here...
return HttpResponse("This response varies based on cookies")

Cache Versioning

Django supports cache versioning which allows you to change the version of the cache without changing the cache keys:

# In view.py file
from django.core.cache import cache


# Increment the version of the cache
cache.incr_version('my_key')

# Decrement the version of the cache
cache.decr_version('my_key')

# Use a specific version of the cache
value = cache.get('my_key', version=2)

Cache versioning allows you to invalidate a group of cache keys when the data changes without manually deleting each key.

from django.core.cache import cache

version = 1 # Increment this number to invalidate the cache
cache.set('my_key', 'my_value', timeout=60*10, version=version)
value = cache.get('my_key', version=version)

Using Redis for Django Sessions

In settings.py, ensure the session engine is set to use the cache:

# settings.py

SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'

Using Redis for Django Celery

If you’re using Celery for task queues, you can configure it to use Redis as the broker and backend:

# settings.py

CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'

Step 7: Monitoring and Management

Redis CLI

Redis provides built-in tools for monitoring, such as the redis-cli. You can interact with your Redis server using the Redis command line interface:

redis-cli monitor
redis-cli monitor

Inside the Redis CLI, you can run commands like KEYS * to list all keys, or FLUSHALL to clear the entire cache.

Django Debug Toolbar

For development Django Debug Toolbar can help you see cache hits and misses:

pip install django-debug-toolbar

Add it to your INSTALLED_APPS and configure it in your settings.py:

# settings.py

INSTALLED_APPS = [
...
'debug_toolbar',
]

MIDDLEWARE = [
...
'debug_toolbar.middleware.DebugToolbarMiddleware',
]

INTERNAL_IPS = [
'127.0.0.1',
]

# Configure the toolbar
DEBUG_TOOLBAR_PANELS = [
'debug_toolbar.panels.cache.CachePanel',
# other panels
]

Include the debug toolbar URLs in your urls.py:

from django.urls import include, path

urlpatterns = [
...
path('__debug__/', include('debug_toolbar.urls')),
]

Step 8:Django Admin and Management Commands

You can also clear the entire cache using Django management commands.

python manage.py cache clear

Step 9: Optimizing Cache Usage

  • Cache only what’s necessary: Avoid caching large, rarely accessed data.
  • Choose appropriate timeouts: Balance between cache hit rate and data freshness.
  • Use cache versioning: To handle cache invalidation gracefully.

Step 10: Additional Tips

  • Avoid cache stampedes: Use techniques like double caching or lock-based mechanisms to prevent multiple processes from regenerating the same cache simultaneously.
  • Use Redis settings: Tune Redis configuration for optimal performance (e.g., max memory settings, eviction policies).

Conclusion

Following this guide, you can effectively use Redis for caching in your Django applications. This setup will help improve the performance and scalability of your application by reducing database load and speeding up response times.

Thank you for reading. If you find something wrong or better ways to do it, let me know in the comments below.

If you like the post, hit the 👏 button below so that others may find it useful. You can follow me on:

GitHub | daily.dev | LinkedIn | YouTube

More Libraries:

Django

28 stories

Python

12 stories

--

--

Django Unleashed
Django Unleashed

Published in Django Unleashed

Unleashing the Full Potential of Web Development

Mehedi Khan
Mehedi Khan

Written by Mehedi Khan

I'm a Software engineer. I'm comfortable with Python, Django, and Full-stack Web Development. Follow To Support Me On Medium 🫠