Files
Pelagic 4e2b0ec0c6
Some checks failed
Lint / Lint (push) Failing after 22s
Performed some general linting. More is needed along with cleanup
2024-05-13 12:53:57 +03:00

143 lines
5.7 KiB
Python

from starfields_drf_generics.utils import sorted_params_string
# TODO classes below that involve create, update, destroy don't delete the
# caches properly, they need a regex cache delete
# TODO put more reasonable asserts and feedback
# Mixin classes that provide cache functionalities
class CacheUniqueUrl:
def get_cache_unique_url(self, request):
"""
Create the query to be cached in a unique way to avoid duplicates.
"""
if not hasattr(self, 'filters_string'):
# Only assign the attribute if it's not already assigned
filters = {}
if self.extra_filters_dict:
filters.update(self.extra_filters_dict)
# Check if the url parameters have any of the keys of the extra
# filters and if so assign them
for key in self.extra_filters_dict:
if key in self.request.query_params.keys():
filters[key] = self.request.query_params[key].replace(
' ', '').split(',')
# Check if they're resolved in the urlconf as well
if key in self.kwargs.keys():
filters[key] = [self.kwargs[key]]
if hasattr(self, 'paged'):
if self.paged:
filters.update({'limit': [self.default_page_size],
'offset': [0]})
if 'limit' in self.request.query_params.keys():
filters.update({
'limit': [self.request.query_params['limit']]})
if 'offset' in self.request.query_params.keys():
filters.update({
'offset': [self.request.query_params['offset']]})
for backend in list(self.filter_backends):
filters.update(backend().get_filters_dict(request, self))
self.filters_string = sorted_params_string(filters)
class CacheGetMixin(CacheUniqueUrl):
cache_prefix = None
cache_vary_on_user = False
cache_timeout_mins = None
default_page_size = 20
extra_filters_dict = None
def get_cache(self, request):
assert self.cache_prefix is not None, (
"'%s' should include a `cache_prefix` attribute"
% self.__class__.__name__
)
self.get_cache_unique_url(request)
# Attempt to get the response from the cache for the whole request
try:
if self.cache_vary_on_user:
cache_attempt = self.cache.get(
f"{self.cache_prefix}.{request.user}.{self.filters_string}"
)
else:
cache_attempt = self.cache.get(
f"{self.cache_prefix}.{self.filters_string}")
except Exception:
self.logger.info(f"Cache get attempt for {self.__class__.__name__}"
" failed.")
cache_attempt = None
if cache_attempt:
return cache_attempt
else:
return None
class CacheSetMixin(CacheUniqueUrl):
cache_prefix = None
cache_vary_on_user = False
cache_timeout_mins = None
default_page_size = 20
extra_filters_dict = None
def set_cache(self, request, response):
self.get_cache_unique_url(request)
# Create a function that programmatically defines the caching function
def make_caching_function(cls, request, cache):
def caching_function(response):
# Writes the response to the cache
try:
if self.cache_vary_on_user:
self.cache.set(key=f"{self.cache_prefix}."
f"{request.user}.{self.filters_string}",
value=response.data,
timeout=60*self.cache_timeout_mins)
else:
self.cache.set(key=f"{self.cache_prefix}"
f".{self.filters_string}",
value=response.data,
timeout=60*self.cache_timeout_mins)
except Exception:
self.logger.exception("Cache set attempt for "
f"{self.__class__.__name__} failed.")
return caching_function
# Register the post rendering hook to the response
caching_function = make_caching_function(self, request, self.cache)
response.add_post_render_callback(caching_function)
class CacheDeleteMixin(CacheUniqueUrl):
cache_delete = True
cache_prefix = None
cache_vary_on_user = False
cache_timeout_mins = None
extra_filters_dict = None
def delete_cache(self, request):
# Handle the caching
if self.cache_delete:
# Create the query to be cached in a unique way to avoid duplicates
self.get_cache_unique_url(request)
assert self.cache_prefix is not None, (
f"{self.__class__.__name__} should include a `cache_prefix`"
"attribute"
)
# Delete the cache since a new entry has been created
try:
if self.cache_vary_on_user:
self.cache.delete(f"{self.cache_prefix}.{request.user}"
f".{self.filters_string}")
else:
self.cache.delete(f"{self.cache_prefix}"
f".{self.filters_string}")
except Exception:
self.logger.exception("Cache delete attempt for "
f"{self.__class__.__name__} failed.")