Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
        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