2

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.

Soviut
  • 88,194
  • 49
  • 192
  • 260
  • did you try to don't overwrite the e.g. list method? pehaps there is an issue on cache wrapping at `CacheResponseMixin`. – trinchet Jul 25 '16 at 18:06

1 Answers1

4

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.

Titus P
  • 959
  • 1
  • 7
  • 16
  • That's what I figured since I'm not calling super in my methods. I couldn't figure out a way to call super and still do the work I needed. – Soviut Jul 29 '16 at 14:53