web/lib/django/views/decorators/cache.py
author ymh <ymh.work@gmail.com>
Thu, 05 Aug 2010 17:28:09 +0200
changeset 50 012451a812f1
parent 38 77b6da96e6f1
permissions -rw-r--r--
Merge with a2711e44ba5de8b1675d7e0ee6aaa4a6c56a9b46
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
38
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     1
"""
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     2
Decorator for views that tries getting the page from the cache and
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     3
populates the cache if the page isn't in the cache yet.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     4
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
The cache is keyed by the URL and some data from the headers. Additionally
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
there is the key prefix that is used to distinguish different cache areas
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     7
in a multi-site setup. You could use the sites.get_current().domain, for
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     8
example, as that is unique across a Django project.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    10
Additionally, all headers from the response's Vary header will be taken into
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    11
account on caching -- just like the middleware does.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    12
"""
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    13
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    14
try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    15
    from functools import wraps
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    16
except ImportError:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    17
    from django.utils.functional import wraps  # Python 2.4 fallback.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    18
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    19
from django.utils.decorators import decorator_from_middleware_with_args, available_attrs
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    20
from django.utils.cache import patch_cache_control, add_never_cache_headers
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    21
from django.middleware.cache import CacheMiddleware
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    22
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    23
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    24
def cache_page(*args, **kwargs):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    25
    # We need backwards compatibility with code which spells it this way:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    26
    #   def my_view(): pass
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    27
    #   my_view = cache_page(my_view, 123)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    28
    # and this way:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    29
    #   my_view = cache_page(123)(my_view)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    30
    # and this:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    31
    #   my_view = cache_page(my_view, 123, key_prefix="foo")
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    32
    # and this:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    33
    #   my_view = cache_page(123, key_prefix="foo")(my_view)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    34
    # and possibly this way (?):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    35
    #   my_view = cache_page(123, my_view)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    36
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    37
    # We also add some asserts to give better error messages in case people are
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    38
    # using other ways to call cache_page that no longer work.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    39
    key_prefix = kwargs.pop('key_prefix', None)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    40
    assert not kwargs, "The only keyword argument accepted is key_prefix"
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    41
    if len(args) > 1:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    42
        assert len(args) == 2, "cache_page accepts at most 2 arguments"
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    43
        if callable(args[0]):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    44
            return decorator_from_middleware_with_args(CacheMiddleware)(cache_timeout=args[1], key_prefix=key_prefix)(args[0])
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    45
        elif callable(args[1]):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    46
            return decorator_from_middleware_with_args(CacheMiddleware)(cache_timeout=args[0], key_prefix=key_prefix)(args[1])
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    47
        else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    48
            assert False, "cache_page must be passed either a single argument (timeout) or a view function and a timeout"
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    49
    else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    50
        return decorator_from_middleware_with_args(CacheMiddleware)(cache_timeout=args[0], key_prefix=key_prefix)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    51
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    52
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    53
def cache_control(**kwargs):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    54
    def _cache_controller(viewfunc):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    55
        def _cache_controlled(request, *args, **kw):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    56
            response = viewfunc(request, *args, **kw)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    57
            patch_cache_control(response, **kwargs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    58
            return response
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    59
        return wraps(viewfunc, assigned=available_attrs(viewfunc))(_cache_controlled)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    60
    return _cache_controller
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    61
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    62
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    63
def never_cache(view_func):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    64
    """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    65
    Decorator that adds headers to a response so that it will
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    66
    never be cached.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    67
    """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    68
    def _wrapped_view_func(request, *args, **kwargs):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    69
        response = view_func(request, *args, **kwargs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    70
        add_never_cache_headers(response)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    71
        return response
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    72
    return wraps(view_func, assigned=available_attrs(view_func))(_wrapped_view_func)