import new from django.core.cache import cache from django.conf import settings from django.http import HttpResponse class HttpResponseServiceUnavailable(HttpResponse): status_code = 503 def get_cell_value(cell): def make_closure_that_returns_value(use_this_value): def closure_that_returns_value(): return use_this_value return closure_that_returns_value dummy_function = make_closure_that_returns_value(0) dummy_function_code = dummy_function.func_code our_function = new.function(dummy_function_code, {}, None, None, (cell,)) value_from_cell = our_function() return value_from_cell def get_decorated_function(function): """ Returns actual decorated function in decorators stack """ while function.func_closure is not None: function = get_cell_value(function.func_closure[0]) return function class limit_request_rate(object): """ Decorator for view that limit request rate for view for concrete user. Anonymous users not limited. @todo: differentiate anonymous users by IP """ CACHE_VAR_PREFIX = "limit_request_rate_" def __init__(self, timeout = None): self.timeout = timeout or settings.DEFAULT_REQUEST_TIMEOUT def __call__(self, function): def actual_decorator(request, *args, **kwargs): if request.user.is_authenticated(): dec_func = get_decorated_function(function) cache_key = self.CACHE_VAR_PREFIX + str(request.user.id) + dec_func .func_name + dec_func.func_code.co_filename if not cache.get(cache_key): cache.set(cache_key, 1, self.timeout) return function(request, *args, **kwargs) else: return HttpResponseServiceUnavailable() return function(request, *args, **kwargs) return actual_decorator