Using Django Ratelimit

Use as a decorator

Import:

from ratelimit.decorators import ratelimit
@ratelimit(group=None, key=, rate=None, method=ALL, block=False)
Parameters:
  • groupNone A group of rate limits to count together. Defaults to the dotted name of the view.
  • key – What key to use, see Keys.
  • rate

    ‘5/m’ The number of requests per unit time allowed. Valid units are:

    • s - seconds
    • m - minutes
    • h - hours
    • d - days

    Also accepts callables. See Rates.

  • methodALL Which HTTP method(s) to rate-limit. May be a string, a list/tuple of strings, or the special values for ALL or UNSAFE (which includes POST, PUT, DELETE and PATCH).
  • blockFalse Whether to block the request instead of annotating.

HTTP Methods

Each decorator can be limited to one or more HTTP methods. The method= argument accepts a method name (e.g. 'GET') or a list or tuple of strings (e.g. ('GET', 'OPTIONS')).

There are two special shortcuts values, both accessible from the ratelimit decorator, the RatelimitMixin class, or the is_ratelimited helper, as well as on the root ratelimit module:

from ratelimit.decorators import ratelimit

@ratelimit(key='ip', method=ratelimit.ALL)
@ratelimit(key='ip', method=ratelimit.UNSAFE)
def myview(request):
    pass

ratelimit.ALL applies to all HTTP methods. ratelimit.UNSAFE is a shortcut for ('POST', 'PUT', 'PATCH', 'DELETE').

Examples

@ratelimit(key='ip', rate='5/m')
def myview(request):
    # Will be true if the same IP makes more than 5 POST
    # requests/minute.
    was_limited = getattr(request, 'limited', False)
    return HttpResponse()

@ratelimit(key='ip', rate='5/m', block=True)
def myview(request):
    # If the same IP makes >5 reqs/min, will raise Ratelimited
    return HttpResponse()

@ratelimit(key='post:username', rate='5/m', method=['GET', 'POST'])
def login(request):
    # If the same username is used >5 times/min, this will be True.
    # The `username` value will come from GET or POST, determined by the
    # request method.
    was_limited = getattr(request, 'limited', False)
    return HttpResponse()

@ratelimit(key='post:username', rate='5/m')
@ratelimit(key='post:password', rate='5/m')
def login(request):
    # Use multiple keys by stacking decorators.
    return HttpResponse()

@ratelimit(key='get:q', rate='5/m')
@ratelimit(key='post:q', rate='5/m')
def search(request):
    # These two decorators combine to form one rate limit: the same search
    # query can only be tried 5 times a minute, regardless of the request
    # method (GET or POST)
    return HttpResponse()

@ratelimit(key='ip', rate='4/h')
def slow(request):
    # Allow 4 reqs/hour.
    return HttpResponse()

rate = lambda r: None if request.user.is_authenticated() else '100/h'
@ratelimit(key='ip', rate=rate)
def skipif1(request):
    # Only rate limit anonymous requests
    return HttpResponse()

@ratelimit(key='user_or_ip', rate='10/s')
@ratelimit(key='user_or_ip', rate='100/m')
def burst_limit(request):
    # Implement a separate burst limit.
    return HttpResponse()

@ratelimit(group='expensive', key='user_or_ip', rate='10/h')
def expensive_view_a(request):
    return something_expensive()

@ratelimit(group='expensive', key='user_or_ip', rate='10/h')
def expensive_view_b(request):
    # Shares a counter with expensive_view_a
    return something_else_expensive()

@ratelimit(key='header:x-cluster-client-ip')
def post(request):
    # Uses the X-Cluster-Client-IP header value.
    return HttpResponse()

@ratelimit(key=lambda r: r.META.get('HTTP_X_CLUSTER_CLIENT_IP',
                                    r.META['REMOTE_ADDR'])
def myview(request):
    # Use `X-Cluster-Client-IP` but fall back to REMOTE_ADDR.
    return HttpResponse()

Class-Based Views

New in version 0.5.

The @ratelimit decorator also works on class-based view methods, though make sure the ``method`` argument matches the decorator:

class MyView(View):
    @ratelimit(key='ip', method='POST')
    def post(self, request, *args):
        # Something expensive...

Note

Unless given an explicit group argument, different methods of a class-based view will be limited separate.

Class-Based View Mixin

class ratelimit.mixins.RatelimitMixin

New in version 0.4.

Ratelimits can also be applied to class-based views with the ratelimit.mixins.RatelimitMixin mixin. They are configured via class attributes that are the same as the decorator, prefixed with ratelimit_, e.g.:

class MyView(RatelimitMixin, View):
    ratelimit_key = 'ip'
    ratelimit_rate = '10/m'
    ratelimit_block = False
    ratelimit_method = 'GET'

    def get(self, request, *args, **kwargs):
        # Calculate expensive report...

Changed in version 0.5: The name of the mixin changed from RateLimitMixin to RatelimitMixin for consistency.

Helper Function

In some cases the decorator is not flexible enough. If this is an issue you use the is_ratelimited helper function. It’s similar to the decorator.

Import:

from ratelimit.utils import is_ratelimited
is_ratelimited(request, group=None, key=, rate=None, method=ALL, increment=False)
Parameters:
  • requestNone The HTTPRequest object.
  • groupNone A group of rate limits to count together. Defaults to the dotted name of the view.
  • key – What key to use, see Keys.
  • rate

    ‘5/m’ The number of requests per unit time allowed. Valid units are:

    • s - seconds
    • m - minutes
    • h - hours
    • d - days

    Also accepts callables. See Rates.

  • methodALL Which HTTP method(s) to rate-limit. May be a string, a list/tuple, or None for all methods.
  • incrementFalse Whether to increment the count or just check.

Exceptions

class ratelimit.exceptions.Ratelimited

If a request is ratelimited and block is set to True, Ratelimit will raise ratelimit.exceptions.Ratelimited.

This is a subclass of Django’s PermissionDenied exception, so if you don’t need any special handling beyond the built-in 403 processing, you don’t have to do anything.

Middleware

There is optional middleware to use a custom view to handle Ratelimited exceptions.

To use it, add ratelimit.middleware.RatelimitMiddleware to your MIDDLEWARE_CLASSES (toward the bottom of the list) and set RATELIMIT_VIEW to the full path of a view you want to use.

The view specified in RATELIMIT_VIEW will get two arguments, the request object (after ratelimit processing) and the exception.