Caching problem with Django Rest Framework

Hei All,

I’ve got an issue on which I’m a bit stuck. I’m trying to cache a DRF viewset with the following:

from django.utils.decorators import method_decorator
from django.views.decorators.vary import vary_on_cookie
from django.core.cache.backends.base import DEFAULT_TIMEOUT
from django.views.decorators.cache import cache_page


class CasesView(generics.ListAPIView):
    serializer_class = CaseSerializer
    permission_classes = [IsAuthenticated]

    def get(self, request, *args, **kwargs):
        species_list = Species.objects.all()
        permitted_species = [species.species for species in species_list]
        species = self.request.query_params.get("species", None)

        if species is not None and species not in permitted_species:
            return Response("Invalid species", status.HTTP_400_BAD_REQUEST)
        return super().get(request, *args, **kwargs)

When hitting the endpoint I get an exception and the exception I am getting is: 'NewCaseAPIView' object has no attribute 'method'. The full stack trace is below.

Anyone have an idea of what I am doing wrong here?



web_1    | Traceback (most recent call last):
web_1    |   File "/usr/local/lib/python3.8/site-packages/django/core/handlers/", line 34, in inner
web_1    |     response = get_response(request)
web_1    |   File "/usr/local/lib/python3.8/site-packages/django/core/handlers/", line 115, in _get_response
web_1    |     response = self.process_exception_by_middleware(e, request)
web_1    |   File "/usr/local/lib/python3.8/site-packages/django/core/handlers/", line 113, in _get_response
web_1    |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
web_1    |   File "/usr/local/lib/python3.8/site-packages/django/utils/", line 130, in _wrapped_view
web_1    |     response = view_func(request, *args, **kwargs)
web_1    |   File "/usr/local/lib/python3.8/site-packages/django/views/decorators/", line 54, in wrapped_view
web_1    |     return view_func(*args, **kwargs)
web_1    |   File "/usr/local/lib/python3.8/site-packages/django/views/generic/", line 71, in view
web_1    |     return self.dispatch(request, *args, **kwargs)
web_1    |   File "/usr/local/lib/python3.8/site-packages/rest_framework/", line 505, in dispatch
web_1    |     response = self.handle_exception(exc)
web_1    |   File "/usr/local/lib/python3.8/site-packages/rest_framework/", line 465, in handle_exception
web_1    |     self.raise_uncaught_exception(exc)
web_1    |   File "/usr/local/lib/python3.8/site-packages/rest_framework/", line 476, in raise_uncaught_exception
web_1    |     raise exc
web_1    |   File "/usr/local/lib/python3.8/site-packages/rest_framework/", line 502, in dispatch
web_1    |     response = handler(request, *args, **kwargs)
web_1    |   File "/usr/local/lib/python3.8/site-packages/rest_framework/", line 208, in get
web_1    |     return self.retrieve(request, *args, **kwargs)
web_1    |   File "/usr/local/lib/python3.8/site-packages/django/utils/", line 122, in _wrapped_view
web_1    |     result = middleware.process_request(request)
web_1    |   File "/usr/local/lib/python3.8/site-packages/django/middleware/", line 132, in process_request
web_1    |     if request.method not in ('GET', 'HEAD'):
web_1    | AttributeError: 'NewCaseAPIView' object has no attribute 'method

I believe the currently-accepted method for caching a class-based view is by specifying the cache in the URL conf.

You’re a gem, Ken! Thank you.

I was actually doing this, but didn’t think it was working, so I tried to see if I could cache the views. Turns out my front-end developer buddy was sending cache-control: no-cache

I also found this link which led me to believe that what I was doing was fine.

It might be the case that it is no longer supported. If it isn’t, I’ll suggest a change to the documentation.



1 Like

I’ve also found that if you want to cache a viewset, then you can add the caching decorator to dispatch()

As an example:

class FurtherReadingViewSet(viewsets.ReadOnlyModelViewSet):

    serializer_class = FurtherReadingSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return FurtherReading.objects.all().filter(

    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

@conor Thanks for sharing this.
Could you please also explain how are you invalidating the cache.