How to Create Custom Throttling Classes in Django REST Framework (DRF)

Last updated 1 month ago | 112 views 75     5

Tags:- Python Django DRF

Introduction: Why Custom Throttling is Essential

Rate limiting is a critical defense mechanism in any public-facing API. Django REST Framework (DRF) provides built-in throttling strategies like AnonRateThrottle and UserRateThrottle, but real-world use cases often demand greater flexibility.

Consider these scenarios:

  • Rate limits based on user subscription tiers (free vs. premium)

  • Throttling per API key or device ID

  • Blocking users based on custom business logic

Custom throttling classes in DRF give you full control over how, when, and for whom you apply rate limits—helping you build smarter, more secure APIs.


What is a Custom Throttle Class?

A custom throttle class is a subclass of DRF's BaseThrottle, SimpleRateThrottle, or another throttle base, where you define your own logic for:

  • Identifying the requester (get_cache_key)

  • Checking whether they’ve exceeded the limit (allow_request)

  • Responding when throttled (throttled)

Let’s walk through how to build one from scratch.


Step-by-Step: Creating a Custom Throttle Class

✅ 1. Choose Your Base Class

DRF offers two main base classes for throttling:

Class Use Case
BaseThrottle Full control; implement all logic manually
SimpleRateThrottle Use DRF's rate-parsing/caching features with a custom identifier

Most cases work well with SimpleRateThrottle.


✅ 2. Subclass and Customize SimpleRateThrottle

from rest_framework.throttling import SimpleRateThrottle

class PremiumUserThrottle(SimpleRateThrottle):
    scope = 'premium_user'  # This links to your settings.py rate

    def get_cache_key(self, request, view):
        # Throttle only authenticated users
        if request.user and request.user.is_authenticated:
            # Custom logic: Only throttle non-premium users
            if not request.user.is_premium:
                return self.cache_format % {
                    'scope': self.scope,
                    'ident': request.user.pk  # Unique identifier
                }
        return None  # Don't throttle premium users

This class will:

  • Throttle only non-premium authenticated users

  • Use their user ID as the identifier

  • Bypass the limit for premium users


✅ 3. Define the Rate in settings.py

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'myapp.throttles.PremiumUserThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'premium_user': '20/minute',
    }
}

✅ 4. Use the Throttle in Views (Optional)

from rest_framework.views import APIView
from rest_framework.response import Response
from myapp.throttles import PremiumUserThrottle

class MyThrottledView(APIView):
    throttle_classes = [PremiumUserThrottle]

    def get(self, request):
        return Response({"message": "This view is protected by custom throttling."})

Complete Functional Code Example

throttles.py

from rest_framework.throttling import SimpleRateThrottle

class SubscriptionThrottle(SimpleRateThrottle):
    scope = 'subscription_throttle'

    def get_cache_key(self, request, view):
        if request.user and request.user.is_authenticated:
            # Use different rate limits for different plans
            self.scope = f"plan_{request.user.subscription_level}"
            return self.cache_format % {
                'scope': self.scope,
                'ident': request.user.pk
            }
        return None  # Skip throttling for anonymous users

settings.py

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': [
        'myapp.throttles.SubscriptionThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'plan_free': '10/minute',
        'plan_pro': '100/minute',
        'plan_enterprise': '1000/minute',
    }
}

views.py

from rest_framework.views import APIView
from rest_framework.response import Response
from myapp.throttles import SubscriptionThrottle

class UserDataView(APIView):
    throttle_classes = [SubscriptionThrottle]

    def get(self, request):
        return Response({"status": "Request allowed based on subscription rate."})

⚠️ Tips & Common Pitfalls

✅ Best Practices

  • Use caching: Ensure your Django cache (e.g. Redis, Memcached) is properly configured.

  • Return informative error messages in throttled responses.

  • Use ScopedRateThrottle when you want per-view or per-scope control.

  • Profile real traffic before setting hard limits.

❌ Common Mistakes

Problem Solution
get_cache_key() returns None DRF skips throttling. Ensure you return a valid identifier.
Misconfigured scope Scope name in class must match keys in DEFAULT_THROTTLE_RATES
Same limits for all users Customize logic with user types, groups, or roles

BaseThrottle vs SimpleRateThrottle vs ScopedRateThrottle

Class Control Level Built-in Rate Support Use Case
BaseThrottle High Fully custom logic
SimpleRateThrottle Medium Custom IDs with rate limiting
ScopedRateThrottle Medium View-specific throttling using throttle_scope

Conclusion: Power Up Your API Throttling

Custom throttling in DRF gives you the power to:

  • Fine-tune access based on user type or behavior

  • Scale your API fairly across user tiers

  • Harden endpoints against specific misuse patterns

Start with SimpleRateThrottle for most use cases, and evolve into BaseThrottle only when needed.

Pro Tip: Combine throttling with authentication, permissions, and caching for full-stack API security and performance.