Caching API Responses With Django And Redis.

Save Bandwidth with Redis.

Rahul Beniwal
3 min readAug 7, 2024

Hello everyone, caching is essential to make a web app great. In this short article, I’ll guide you through setting up caching for your Django API responses using Redis.

Setup

You can see my article 👇 to set up Django in your system using Docker and more.

Project Structure

First, install the necessary dependencies:

pip install django-redis==5.4.0
.
├── db.sqlite3
├── dj_with_redis
│ ├── asgi.py
│ ├── __init__.py
│ ├── __pycache__
│ ├── redis.py
│ ├── settings.py
│ ├── urls.py
│ ├── views.py
│ └── wsgi.py
├── manage.py
├── pyrightconfig.json

Configuration

views.py

from django.http import JsonResponse

def dummy_view(request):
print("Inside Dummy View")
return JsonResponse({
"message": "Dummy View."
})

urls.py

from django.urls import path
from dj_with_redis.views import dummy_view


urlpatterns = [
path("", dummy_view, name="dummy_view")
]

settings.py

Update the settings.py to configure the cache:

CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://localhost:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient"
},
}
}

Initial Test

When you request the homepage, you get the following response:

{"message": "Dummy View."}

And in the logs, you see:

Inside Dummy View
[07/Aug/2024 14:55:31] "GET / HTTP/1.1" 200 26
Inside Dummy View
[07/Aug/2024 14:55:31] "GET / HTTP/1.1" 200 26

Notice that the view is being called every time. Let’s fix this by implementing Redis caching.

Implementing Redis Cache

Create a redis.py file in the same directory as views.py:

import json
from functools import wraps
from django.core.cache import caches
from django.http import JsonResponse as Response

redis_client = caches['default'].client

class Cache(object):
@classmethod
def get(cls, key):
value = redis_client.get(key)
if isinstance(value, bytes):
value = value.decode()
return value

@classmethod
def set(cls, key, value, ttl=0):
redis_client.set(*[key, value, ttl])

@classmethod
def cache_api_response(
cls,
key=None,
timeout=60*60,
status_code=200,
):
"""Decorator can cache the response of an api.

Usage:
@action(detail=False, methods=["get"], url_path="dummy-api")
@cache_reponse(timeout=60 * 60)
def view(request):

You can also configure response class to support both Django and DRF Views.
"""

def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
nonlocal key
nonlocal timeout

if not key:
key = func.__name__
cache_data = cls.get(key)
if cache_data:
data = json.loads(cache_data)
return Response(data, status=status_code)
else:
response = func(*args, **kwargs)
data = response.content.decode("utf-8")
cls.set(key, data, timeout)
return response

return wrapper

return decorator

Hint: You can change response.content to json.dump(response.data) and similar changes to support DRF views.

Updating the View

Update dummy_view to use the cache:

from django.http import JsonResponse
from .redis import Cache


@Cache.cache_api_response()
def dummy_view(request):
print("Inside Dummy View")
return JsonResponse({
"message": "Dummy View."
})

Testing the Cache

Now, when you make requests, you will see that the response is cached for 1 hour:

Inside Dummy View
[07/Aug/2024 15:33:12] "GET / HTTP/1.1" 200 26
[07/Aug/2024 15:33:12] "GET / HTTP/1.1" 200 26
[07/Aug/2024 15:33:13] "GET / HTTP/1.1" 200 26

Conclusion

Implementing caching with Redis in Django can significantly improve the performance of your web application by reducing the load on your server and speeding up response times.

If you found it helpful, Leave a 👏 and follow Rahul Beniwal for more upcoming articles.

Other similar articles by me.

--

--

Rahul Beniwal

Pythoneer | Django Expert | Concurrency Buff | Rust Fan | Backend Aficionado | Python Workflow Optimizer | Scaling & Deployment Tips | Simplifying Complex Code!