From 3614e0656c357e27dec1dfdd5f538f4c6ecc4860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Tue, 13 Sep 2016 21:03:43 +0200 Subject: [PATCH] cache api responses --- src/c3nav/api/views/cache.py | 41 ++++++++++++++++++++++++++++++++++ src/c3nav/api/views/mapdata.py | 7 +++--- 2 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 src/c3nav/api/views/cache.py diff --git a/src/c3nav/api/views/cache.py b/src/c3nav/api/views/cache.py new file mode 100644 index 00000000..51b73021 --- /dev/null +++ b/src/c3nav/api/views/cache.py @@ -0,0 +1,41 @@ +import base64 + +from django.core.cache import cache +from django.utils.cache import patch_vary_headers + +from ..permissions import get_unlocked_packages + + +class CachedViewSetMixin: + def get_cache_key(self, request): + cache_key = ('api__' + ('OPTIONS' if request.method == 'OPTIONS' else 'GET') + '_' + + base64.b64encode(self.get_cache_params(request).encode()).decode() + '_' + + request.path + '?' + request.META['QUERY_STRING']) + return cache_key + + def get_cache_params(self, request): + return '' + + def dispatch(self, request, *args, **kwargs): + do_cache = request.method in ('GET', 'HEAD', 'OPTIONS') + if do_cache: + cache_key = self.get_cache_key(request) + if cache_key in cache: + return cache.get(cache_key) + response = super().dispatch(request, *args, **kwargs) + patch_vary_headers(response, ['Cookie']) + if do_cache: + response.render() + cache.set(cache_key, response, 60) + return response + + @property + def default_response_headers(self): + headers = super().default_response_headers + headers['Vary'] += ', Cookie' + return headers + + +class AccessCachedViewSetMixin(CachedViewSetMixin): + def get_cache_params(self, request): + return super().get_cache_params(request)+'___'+'___'.join(get_unlocked_packages(request)) diff --git a/src/c3nav/api/views/mapdata.py b/src/c3nav/api/views/mapdata.py index 27a18d8b..b2d6cc81 100644 --- a/src/c3nav/api/views/mapdata.py +++ b/src/c3nav/api/views/mapdata.py @@ -11,9 +11,10 @@ from rest_framework.viewsets import ReadOnlyModelViewSet from ...mapdata.models import Level, Package, Source from ..permissions import filter_source_queryset from ..serializers import LevelSerializer, PackageSerializer, SourceSerializer +from .cache import AccessCachedViewSetMixin, CachedViewSetMixin -class LevelViewSet(ReadOnlyModelViewSet): +class LevelViewSet(CachedViewSetMixin, ReadOnlyModelViewSet): """ Returns a list of all levels on the map. """ @@ -26,7 +27,7 @@ class LevelViewSet(ReadOnlyModelViewSet): search_fields = ('name',) -class PackageViewSet(ReadOnlyModelViewSet): +class PackageViewSet(AccessCachedViewSetMixin, ReadOnlyModelViewSet): """ Returns a list of all packages the map consists of. """ @@ -39,7 +40,7 @@ class PackageViewSet(ReadOnlyModelViewSet): search_fields = ('name',) -class SourceViewSet(ReadOnlyModelViewSet): +class SourceViewSet(AccessCachedViewSetMixin, ReadOnlyModelViewSet): """ Returns a list of source images (to use as a drafts). Call /sources/{name}/image to get the image.