'Django still caching views with @never_cache decorator

I'm using Django with Django Rest Framework and uWSGI. I have memcached set up on the server with pylibmc backend. I have Django configured for per-site cache so every view should be cached except ones that I exempt from it using the @never_cache decorator. I can't figure out why Django is still trying to cache my API views even with Django's @never_cache decorator added. I have an API that supports read write operations for a Draft model. When I make a draft update using the UpdateAPIView, then refresh the page, it is still showing the Draft data prior to the update. I've confirmed it's not browser side cache because network logs show 200 response, not 304, and if I clear memcached and refresh the page, then the updated Draft is correctly returned.

This recently happened when I upgraded Django from 1.8 to 1.10, the ~15 pip package dependencies, the OS distro and its packages (so it's hard to pinpoint exactly what caused it).

DRF Retrieve API View

from django.views.decorators.cache import never_cache

class DraftDetail(generics.RetrieveAPIView):
    queryset = Draft.objects.all()
    serializer_class = DraftSerializer
    permission_classes = (permissions.IsAuthenticated, HasReadWriteAccess)

    @never_cache
    def dispatch(self, *args, **kwargs):
        return super(DraftDetail, self).dispatch(*args, **kwargs)

I've also tried the alternate class based @method_decorator but no change:

from django.views.decorators.cache import never_cache
from django.utils.decorators import method_decorator

@method_decorator(never_cache, name='dispatch')
class DraftDetail(generics.RetrieveAPIView):
    queryset = Draft.objects.all()
    serializer_class = DraftSerializer
    permission_classes = (permissions.IsAuthenticated, HasReadWriteAccess)

settings.py

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
        'LOCATION': '127.0.0.1:11211',
    }
}
PYLIBMC_MIN_COMPRESS_LEN = 250
# The cache alias to use for storage.
CACHE_MIDDLEWARE_ALIAS = 'default'
# The number of seconds each page should be cached.
CACHE_MIDDLEWARE_SECONDS = 500
CACHE_MIDDLEWARE_KEY_PREFIX = 'app'

MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    (...),
    'django.middleware.cache.FetchFromCacheMiddleware',
)

I also have Cache-Control:max-age=0 set in my request headers.



Solution 1:[1]

Maybe

@method_decorator(never_cache())

Solution 2:[2]

Even when you are adding a decorator to the dispatch method, you should use the method_decorator.

Django's official documents says:

A method on a class isn’t quite the same as a standalone function, so you can’t just apply a function decorator to the method – you need to transform it into a method decorator first.

The never_cache decorator doesn't get any arguments; so it should be used without parentheses. So maybe this works:

@method_decorator(never_cache)
def dispatch(self, request, *args, **kwargs):
    ....

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 adiga
Solution 2