Search code examples
djangocachingdjango-rest-frameworkdrf-extensions

Why isn't the drf-extensions CacheResponseMixin caching?


I'm using Django Rest Framework and the DRF-Extensions for caching.

I have a viewset with custom list() and retrieve() methods. I can put @cache_response() decorators on the methods and it successfully gets and sets to the cache. However, if I try to use CacheResponseMixin nothing happens.

Works:

class SeriesViewSet(viewsets.ReadOnlyModelViewSet):
    serializer_class = SeriesSerializer

    def get_queryset(self):
        series_type = EntityType.objects.get(name='series')
        return Container.objects.filter(type=series_type)

    @cache_response()
    def list(self, request):
        series = self.get_queryset()
        serializer = SeriesSerializer(series, many=True)
        return Response(serializer.data)

    @cache_response()
    def retrieve(self, request, pk=None):
        name = pk
        series = self.get_queryset()
        show = series.get(data__title=name)
        serializer = SeriesSerializer(show)
        return Response(serializer.data)

Does NOT work:

class SeriesViewSet(CacheResponseMixin, viewsets.ReadOnlyModelViewSet):
    serializer_class = SeriesSerializer

    def get_queryset(self):
        series_type = EntityType.objects.get(name='series')
        return Container.objects.filter(type=series_type)

    def list(self, request):
        series = self.get_queryset()
        serializer = SeriesSerializer(series, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        name = pk
        series = self.get_queryset()
        show = series.get(data__title=name)
        serializer = SeriesSerializer(show)
        return Response(serializer.data)

No errors are given, my cache entry simply doesn't get created.


Solution

  • Reading the source (as well as the docs), it looks like the mixin class is ONLY for use when you use the default list and retrieve functions. Check the source:

    # -*- coding: utf-8 -*-
    from rest_framework_extensions.cache.decorators import cache_response
    from rest_framework_extensions.settings import extensions_api_settings
    
    
    class BaseCacheResponseMixin(object):
        # todo: test me. Create generic test like
        # test_cache_reponse(view_instance, method, should_rebuild_after_method_evaluation)
        object_cache_key_func = extensions_api_settings.DEFAULT_OBJECT_CACHE_KEY_FUNC
        list_cache_key_func = extensions_api_settings.DEFAULT_LIST_CACHE_KEY_FUNC
    
    
    class ListCacheResponseMixin(BaseCacheResponseMixin):
        @cache_response(key_func='list_cache_key_func')
        def list(self, request, *args, **kwargs):
            return super(ListCacheResponseMixin, self).list(request, *args, **kwargs)
    
    
    class RetrieveCacheResponseMixin(BaseCacheResponseMixin):
        @cache_response(key_func='object_cache_key_func')
        def retrieve(self, request, *args, **kwargs):
            return super(RetrieveCacheResponseMixin, self).retrieve(request, *args, **kwargs)
    
    
    class CacheResponseMixin(RetrieveCacheResponseMixin,
                             ListCacheResponseMixin):
        pass
    

    As you can see, it defines its own list and retrieve methods. When you write yours in your viewset class, it bypasses these ones completely.

    So, the answer is to use the decorators when you need to write your own list and retrieve functions, or, if you can use the default list and retrieve functions built into the view/viewset, then use the mixin class.