import hashlib
from django.core.cache import cache
def try_cache_first(timeout=300):
"""
Tries to get the output of the function from the cache firsts. Otherwise,
computes the function and stores the result in the cache.
You can also pass the timeout in seconds for the cached value. By default,
this is 5 minutes.
Example usage, which holds the value of expensive_function in the cache for
10 minutes:
@try_cache_first(timeout=600)
def expensive_function():
<do expensive stuff>
return result
All results are indexed by a hash of the function name and parameters,
so changes to function inputs should refresh the cache automatically.
"""
def decorator(func):
def wrapper(*args, **kwargs):
# Build keys from function name and arguments
caching_keys = [func.__name__]
if args is not None:
caching_keys.extend(args)
if kwargs is not None:
caching_keys.extend(sorted(kwargs.iteritems()))
# have to sort the caching keys because kwargs can be in random
# order which screws with hashing the inputs.
# Convert the keys to a big string and hash it
caching_keys = map(str, caching_keys)
cache_key = '_'.join(caching_keys)
cache_key = hashlib.sha512(cache_key).hexdigest()
cache_key = cache_key[:250] # max size of caching keys in memcached
# Fetch from cache
output = cache.get(cache_key)
if output is None:
output = func(*args, **kwargs)
cache.set(cache_key, output, timeout)
return output
return wrapper
return decorator
Comments
nice, but what if the real result to be cached is None ? IMHO you shoud encode None-result differ than None-absence-in-cache...
#