DEV Community

Vincent Tommi
Vincent Tommi

Posted on

🚦 Throttling in Django REST Framework: Step-by-Step Guide for Beginners

What is Throttling?
Throttling is a technique used to control the number of requests a client can make to an API over a specific time period. This helps:

  • Prevent API abuse

  • Ensure fair usage

  • Reduce server load

In this tutorial, we’ll build a simple Django REST API with throttling, allowing a maximum of 2 submissions per IP in 24 hours.

🏗️ Step 1: Set Up the Django Project

Create a new Django project:
django-admin startproject throttling
Enter fullscreen mode Exit fullscreen mode

Create a new app inside the project:

cd throttling
python manage.py startapp core
Enter fullscreen mode Exit fullscreen mode

Install Django REST Framework:

pip install djangorestframework
Enter fullscreen mode Exit fullscreen mode

Add the apps to INSTALLED_APPS in throttling/settings.py:

INSTALLED_APPS = [
    ...
    'rest_framework',
    'core',
]

Enter fullscreen mode Exit fullscreen mode

⚙️ Step 2: Optional Global Throttle Settings
You can set default throttling behavior in settings.py

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '2/min',  # 2 request per minute for anonymous users
    }
}

Enter fullscreen mode Exit fullscreen mode

In this guide, we’ll use custom per-view throttling instead.

📦 Step 3: Create the Book Model
In core/models.py:

from django.db import models

class Book(models.Model):
    name = models.CharField(max_length=100)
    genre = models.CharField(max_length=50)
    created_at = models.DateField(auto_now_add=True)
    ip_address = models.GenericIPAddressField(null=True, blank=True)

    class Meta:
        ordering = ['-created_at']
        verbose_name = 'Book'

    def __str__(self):
        return f"{self.name} - {self.ip_address}"

Enter fullscreen mode Exit fullscreen mode

Apply the migrations:

python manage.py makemigrations core
python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

🔄 Step 4: Create a Serializer
In core/serializer.py:

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['id', 'name', 'genre', 'ip_address', 'created_at']

Enter fullscreen mode Exit fullscreen mode

📡 Step 5: Create the View with Throttling Logic
In core/views.py:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from datetime import datetime, timedelta

from .models import Book
from .serializers import BookSerializer

class BookAPIView(APIView):

    def get_client_ip(self, request):
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip

    def get(self, request):
        books = Book.objects.all()
        serializer = BookSerializer(books, many=True)
        return Response({
            "message": "Successfully retrieved books",
            "status": "success",
            "data": serializer.data
        }, status=status.HTTP_200_OK)

    def post(self, request):
        ip = self.get_client_ip(request)
        time_limit = datetime.now() - timedelta(hours=24)

        submissions_count = Book.objects.filter(
            ip_address=ip, created_at__gte=time_limit).count()

        if submissions_count >= 2:
            return Response({
                "message": "Submission limit reached. Max 2 per 24 hours from the same IP.",
                "status": "error"
            }, status=status.HTTP_429_TOO_MANY_REQUESTS)

        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(ip_address=ip)
            return Response({
                "message": "Successfully posted book",
                "status": "success",
                "data": serializer.data
            }, status=status.HTTP_201_CREATED)

        return Response({
            "message": "Failed to create book",
            "status": "error",
            "errors": serializer.errors
        }, status=status.HTTP_400_BAD_REQUEST)

Enter fullscreen mode Exit fullscreen mode

🧭 Step 6: Setup URLs
In core/urls.py:

from django.urls import path
from .views import BookAPIView

urlpatterns = [
    path('', BookAPIView.as_view(), name='book'),
]

Enter fullscreen mode Exit fullscreen mode

In throttling/urls.py:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/core', include('core.urls')),
]
Enter fullscreen mode Exit fullscreen mode

✅ Step 7: Test the API
Start your development server

python manage.py runserver
Enter fullscreen mode Exit fullscreen mode

Send a GET request to /api/core → returns a list of books to see

Image description
But when you try to request continually you see as below throttling is working by controlling the rate at which clients can make requests to API.

Image description

Top comments (0)