Skip Django Rest Throttling Counter

Viewed 81

How can I prevent Django rest throttling count the request when the user request is invalid or the server failed to complete the process?

For example, I need params from the user, but when the user does not give the params, Django rest throttling still counts it.

Is there any solution to skipping the throttling counter when the request is not successful?

Example

class OncePerHourAnonThrottle(AnonRateThrottle):
    rate = "1/hour"


class Autoliker(APIView):
    throttle_classes = [OncePerHourAnonThrottle]

    def get(self, request):
        content = {"status": "get"}
        return Response(content)

    def post(self, request):
        post_url = request.POST.get("url", None)
        print(post_url)

        content = {"status": "post"}
        return Response(content)

    def throttled(self, request, wait):
        raise Throttled(
            detail={
                "message": "request limit exceeded",
                "availableIn": f"{wait} seconds",
                "throttleType": "type",
            }
        )
1 Answers

You can create a decorator to do so.


class OncePerHourAnonThrottle(AnonRateThrottle):
    rate = "1/hour"

    def allow_request(self, request, view):
        """
        This function is copy of SimpleRateThrottle.allow_request
        The only difference is, instead of executing self.throttle_success
        it directly returns True and doesn't mark this request as success yet.
        """
        if self.rate is None:
            return True

        self.key = self.get_cache_key(request, view)
        if self.key is None:
            return True

        self.history = self.cache.get(self.key, [])
        self.now = self.timer()

        # Drop any requests from the history which have now passed the
        # throttle duration
        while self.history and self.history[-1] <= self.now - self.duration:
            self.history.pop()
        if len(self.history) >= self.num_requests:
            return False
        return True

def rate_limiter(view_function):
    @wraps(view_function)
    def inner(view_obj, request, *args, **kwargs):
        throttle = OncePerHourAnonThrottle()
        allowed = throttle.allow_request(request, None)
        if not allowed:
            raise exceptions.Throttled(throttle.wait())
        try:
            response = view_function(view_obj, request, *args, **kwargs)
        except Exception as exc:
            response = view_obj.handle_exception(exc)
        if response.status_code == 200:
            # now if everything goes OK, count this request as success
            throttle.throttle_success()
        return response

    return inner

class Autoliker(APIView):
   
    @rate_limiter
    def post(requests):
        # view logic
        pass

This is the basic idea how you can do it, now you can make it a generic decorator or even class based decorator.

Related