from functools import wraps
from typing import Callable, List, Optional
from django.core.cache import caches
def _generate_cache_key ( func , args , kwargs , exclude ) :
func_args = func.__code__.co_varnames
named_args = {k: v for k, v in zip ( func_args , args )}
named_args. update ( kwargs )
named_args. pop ( key , None )
return f " { func.__module__ } . { func.__name__ } . { named_args } "
def _get_cache ( cache_backend_name : str , default_cache_backend_name : str = " default " ) :
if cache_backend_name in caches:
return caches[cache_backend_name]
return caches[default_cache_backend_name]
def _set_cache ( cache , key , value , timeout , skip_cache_on= []) :
if value not in skip_cache_on:
cache. set ( key , value , timeout )
def cache_decorator ( cache_backend_name : str = " default " , timeout : int = 60 , exclude : Optional[List] = [] ,
fallback_cache_backend_name : str = " default " , skip_cache_on : Optional[List] = []) -> Callable:
Decorator to cache the results of a function
:param cache_name: The name of the cache backend to use
:param timeout: The timeout of the cache
:param exclude: List of arguments to exclude from the cache key
:param fallback_cache_backend_name: The name of the cache backend to use in case of cache backend not found
:param skip_cache_on: List of values to skip caching
def wrapper ( *args , **kwargs ) :
key = _generate_cache_key ( func , args , kwargs , exclude )
cache = _get_cache ( cache_backend_name , fallback_cache_backend_name )
value = func ( * args , ** kwargs )
return _set_cache ( cache , key , value , timeout , skip_cache_on )
def cache_update ( *args , **kwargs ) :
key = _generate_cache_key ( func , args , kwargs , exclude )
cache = _get_cache ( cache_backend_name , fallback_cache_backend_name )
value = func ( * args , ** kwargs )
return _set_cache ( cache , key , value , timeout , skip_cache_on )
wrapper.cache_update = cache_update