def wrapped(context, request, *args, **kwargs): viewsets = settings.ULTRACACHE.get("drf", {}).get("viewsets", {}) dotted_name = context.__module__ + "." + context.__class__.__name__ do_cache = (dotted_name in viewsets) or (context.__class__ in viewsets) or ("*" in viewsets) if do_cache: li = [request.get_full_path()] viewset_settings = viewsets.get(dotted_name, {}) \ or viewsets.get(context.__class__, {}) \ or viewsets.get("*", {}) evaluate = viewset_settings.get("evaluate", None) if evaluate is not None: if callable(evaluate): li.append(evaluate(context, request)) else: li.append(eval(evaluate)) if "django.contrib.sites" in settings.INSTALLED_APPS: li.append(get_current_site_pk(request)) s = ":".join([str(l) for l in li]) cache_key = hashlib.md5(s.encode("utf-8")).hexdigest() cached = cache.get(cache_key, None) if cached is not None: response = Response(pickle.loads(cached["content"])) # Headers has a non-obvious format for k, v in cached["headers"].items(): response[v[0]] = v[1] return response if not hasattr(request, "_ultracache"): setattr(request, "_ultracache", []) setattr(request, "_ultracache_cache_key_range", []) response = func(context, request, *args, **kwargs) if do_cache: cache_meta(_thread_locals.ultracache_recorder, cache_key, request=request) response = context.finalize_response(request, response, *args, **kwargs) response.render() timeout = viewset_settings.get("timeout", 300) headers = getattr(response, "_headers", {}) cache.set(cache_key, { "content": pickle.dumps(response.data), "headers": headers }, timeout) return response else: return response
def render(self, context): try: expire_time = self.expire_time_var.resolve(context) except VariableDoesNotExist: raise TemplateSyntaxError( "ultracache tag got an unknown variable: %r" % self.expire_time_var.var ) try: expire_time = int(expire_time) except (ValueError, TypeError): raise TemplateSyntaxError( "ultracache tag got a non-integer timeout value: %r" % expire_time ) request = context["request"] # If request not GET or HEAD never cache if request.method.lower() not in ("get", "head"): return self.nodelist.render(context) # Set a list on the request. Django's template rendering is recursive # and single threaded so we can use a list to keep track of contained # objects. if not hasattr(request, "_ultracache"): setattr(request, "_ultracache", []) start_index = 0 else: start_index = len(request._ultracache) vary_on = [] if "django.contrib.sites" in settings.INSTALLED_APPS: vary_on.append(str(settings.SITE_ID)) for var in self.vary_on: try: r = var.resolve(context) except VariableDoesNotExist: pass if isinstance(r, Promise): r = unicode(r) vary_on.append(r) cache_key = make_template_fragment_key(self.fragment_name, vary_on) value = cache.get(cache_key) if value is None: value = self.nodelist.render(context) cache.set(cache_key, value, expire_time) cache_meta(request, cache_key, start_index) else: # A cached result was found. Set tuples in _ultracache manually so # outer template tags are aware of contained objects. for tu in cache.get(cache_key + "-objs", []): request._ultracache.append(tu) return value
def render(self, context): try: expire_time = self.expire_time_var.resolve(context) except VariableDoesNotExist: raise TemplateSyntaxError( "ultracache tag got an unknown variable: %r" % self.expire_time_var.var ) try: expire_time = int(expire_time) except (ValueError, TypeError): raise TemplateSyntaxError( "ultracache tag got a non-integer timeout value: %r" % expire_time ) request = context["request"] # If request not GET or HEAD never cache if request.method.lower() not in ("get", "head"): return self.nodelist.render(context) # Set a list on the request. Django's template rendering is recursive # and single threaded so we can use a list to keep track of contained # objects. if not hasattr(request, "_ultracache"): setattr(request, "_ultracache", []) start_index = 0 else: start_index = len(request._ultracache) vary_on = [] if "django.contrib.sites" in settings.INSTALLED_APPS: vary_on.append(str(get_current_site_pk(request))) for var in self.vary_on: try: r = var.resolve(context) except VariableDoesNotExist: pass if isinstance(r, Promise): r = unicode(r) vary_on.append(r) cache_key = make_template_fragment_key(self.fragment_name, vary_on) value = cache.get(cache_key) if value is None: value = self.nodelist.render(context) cache.set(cache_key, value, expire_time) cache_meta(request, cache_key, start_index) else: # A cached result was found. Set tuples in _ultracache manually so # outer template tags are aware of contained objects. for tu in cache.get(cache_key + "-objs", []): request._ultracache.append(tu) return value
def wrapped(context, request, *args, **kwargs): viewsets = settings.ULTRACACHE.get("drf", {}).get("viewsets", {}) do_cache = (context.__class__ in viewsets) or ("*" in viewsets) if do_cache: li = [request.get_full_path()] viewset_settings = viewsets.get(context.__class__, {}) \ or viewsets.get("*", {}) evaluate = viewset_settings.get("evaluate", None) if evaluate is not None: li.append(eval(evaluate)) if "django.contrib.sites" in settings.INSTALLED_APPS: li.append(settings.SITE_ID) cache_key = md5.new(":".join([str(l) for l in li])).hexdigest() cached_response = cache.get(cache_key, None) if cached_response is not None: return cached_response obj_or_queryset, response = func(context, request, *args, **kwargs) if do_cache: if not hasattr(request, "_ultracache"): setattr(request, "_ultracache", []) try: iter(obj_or_queryset) except TypeError: obj_or_queryset = [obj_or_queryset] for obj in obj_or_queryset: # get_for_model itself is cached ct = ContentType.objects.get_for_model(obj.__class__) request._ultracache.append((ct.id, obj.pk)) cache_meta(request, cache_key) response = context.finalize_response(request, response, *args, **kwargs) response.render() evaluate = viewset_settings.get("timeout", 300) cache.set(cache_key, response, 300) return response else: return response
def _wrapped_view(view_or_request, *args, **kwargs): # The type of the request gets muddled when using a function based # decorator. We must use a function based decorator so it can be # used in urls.py. request = getattr(view_or_request, "request", view_or_request) if not hasattr(_thread_locals, "ultracache_request"): setattr(_thread_locals, "ultracache_request", request) # If request not GET or HEAD never cache if request.method.lower() not in ("get", "head"): return view_func(view_or_request, *args, **kwargs) # If request contains messages never cache l = 0 try: l = len(request._messages) except (AttributeError, TypeError): pass if l: return view_func(view_or_request, *args, **kwargs) # Compute a cache key li = [str(view_or_request.__class__), view_func.__name__] # request.get_full_path is implicitly added it no other request # path is provided. get_full_path includes the querystring and is # the more conservative approach but makes it trivially easy for a # request to bust through the cache. if not set(params).intersection( set(("request.get_full_path()", "request.path", "request.path_info"))): li.append(request.get_full_path()) if "django.contrib.sites" in settings.INSTALLED_APPS: li.append(get_current_site_pk(request)) # Pre-sort kwargs keys = list(kwargs.keys()) keys.sort() for key in keys: li.append("%s,%s" % (key, kwargs[key])) # Extend cache key with custom variables for param in params: if not isinstance(param, str): param = str(param) li.append(eval(param)) s = ":".join([str(l) for l in li]) hashed = hashlib.md5(s.encode("utf-8")).hexdigest() cache_key = "ucache-get-%s" % hashed cached = cache.get(cache_key, None) if cached is None: # The get view as outermost caller may bluntly set _ultracache request._ultracache = [] response = view_func(view_or_request, *args, **kwargs) content = None if isinstance(response, TemplateResponse): content = response.render().rendered_content elif isinstance(response, HttpResponse): content = response.content if content is not None: headers = getattr(response, "_headers", {}) cache.set(cache_key, { "content": content, "headers": headers }, timeout) cache_meta(request, cache_key) else: response = HttpResponse(cached["content"]) # Headers has a non-obvious format for k, v in cached["headers"].items(): response[v[0]] = v[1] return response
def _wrapped_view(view_or_request, *args, **kwargs): # The type of the request gets muddled when using a function based # decorator. We must use a function based decorator so it can be # used in urls.py. request = getattr(view_or_request, "request", view_or_request) # If request not GET or HEAD never cache if request.method.lower() not in ("get", "head"): return view_func(view_or_request, *args, **kwargs) # If request contains messages never cache l = 0 try: l = len(request._messages) except (AttributeError, TypeError): pass if l: return view_func(view_or_request, *args, **kwargs) # Compute a cache key li = [str(view_or_request.__class__), view_func.__name__] # request.get_full_path is implicitly added it no other request # path is provided. get_full_path includes the querystring and is # the more conservative approach but makes it trivially easy for a # request to bust through the cache. if not set(params).intersection(set(( "request.get_full_path()", "request.path", "request.path_info" ))): li.append(request.get_full_path()) if "django.contrib.sites" in settings.INSTALLED_APPS: li.append(settings.SITE_ID) # Pre-sort kwargs keys = kwargs.keys() keys.sort() for key in keys: li.append("%s,%s" % (key, kwargs[key])) # Extend cache key with custom variables for param in params: if not isinstance(param, types.StringType): param = str(param) li.append(eval(param)) hashed = md5.new(":".join([str(l) for l in li])).hexdigest() cache_key = "ucache-get-%s" % hashed cached = cache.get(cache_key, None) if cached is None: # The get view as outermost caller may bluntly set _ultracache request._ultracache = [] response = view_func(view_or_request, *args, **kwargs) content = getattr(response, "rendered_content", None) \ or getattr(response, "content", None) if content is not None: headers = getattr(response, "_headers", {}) cache.set( cache_key, {"content": content, "headers": headers}, timeout ) cache_meta(request, cache_key) else: response = HttpResponse(cached["content"]) # Headers has a non-obvious format for k, v in cached["headers"].items(): response[v[0]] = v[1] return response