Scalable and invalidateble cache_page decorator

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from django.core.cache import cache
from django.template.defaultfilters import slugify
from django.http import HttpResponse
from django.conf import settings

CACHE_KEY_PREFIX = settings.CACHE_MIDDLEWARE_KEY_PREFIX + 'cache-page:'

def invalidate_cache(url, html5=None):
    """Does cache invalidation for a given URL"""
    cache.set(make_cache_key(url, html5), None)

def invalidate_all_cached_pages():
    """Invalidates all cached pages at once."""
    keys = [key for key in cache._cache.keys() if key.startswith(CACHE_KEY_PREFIX)]
    cache.set_many(dict([(key, None) for key in keys]))

def make_cache_key(url, html5=None):
    key = CACHE_KEY_PREFIX + slugify(url)

    if html5 == True:
        key = '.'.join([key, 'html5'])
    elif html5 == False:
        key = '.'.join([key, 'html4'])

    return key

def cache_page(arg=None): # 1 day as default
    """This decorator works in replacement to Django's decorator with same name, but
    it doesn't use Django's middleware system to make cache key, so, it uses its own
    logic to do it and make possible invalidate cache.
    
    This decorator shouldn't be used to views with user-based data."""

    default_exp = 60 * 30 # 30 minutes

    def _wrapper(func):
        def _inner(request, *args, **kwargs):
            key = make_cache_key(request.get_full_path(), getattr(request, 'supports_html5', None))
            content = cache.get(key, None)

            if not content:
                resp = func(request, *args, **kwargs)
                content = resp.content

                # Only stores in cache if is a regular HttpResponse returning text/html
                if resp.__class__.__name__ == 'HttpResponse' and\
                   getattr(resp, 'mimetype', 'text/html') == 'text/html':
                    cache.set(key, content, expiration)
                else:
                    return resp

            return HttpResponse(content)
        return _inner

    if callable(arg):
        expiration = default_exp
        return _wrapper(arg)
    else:
        expiration = arg or default_exp 
        return _wrapper

More like this

  1. Cache Any Function by jeffwheeler 7 years, 1 month ago
  2. Get the Django decorator/middleware cache key for given URL by s29 2 years, 5 months ago
  3. Sorl Thumbnail + Amazon S3 by skoczen 4 years, 10 months ago
  4. Caching tag with singnal-based invalidation by rushman 6 years, 1 month ago
  5. Use memcached to throttle POSTs by coleifer 3 years, 11 months ago

Comments

(Forgotten your password?)