Вопрос

I'm trying to do cache_page with class based views (TemplateView) and i'm not able to. I followed instructions here:

Django--URL Caching Failing for Class Based Views

as well as here:

https://github.com/msgre/hazard/blob/master/hazard/urls.py

But I get this error:

cache_page has a single mandatory positional argument: timeout

I read the code for cache_page and it has the following:

if len(args) != 1 or callable(args[0]):
    raise TypeError("cache_page has a single mandatory positional argument: timeout")
cache_timeout = args[0]

which means it wont allow more than 1 argument. Is there any other way to get cache_page to work?? I have been digging into this for sometime...

It seems like the previous solutions wont work any longer

Это было полезно?

Решение

According to the caching docs, the correct way to cache a CBV in the URLs is:

from django.views.decorators.cache import cache_page

url(r'^my_url/?$', cache_page(60*60)(MyView.as_view())),

Note that the answer you linked to is out of date. The old way of using the decorator has been removed (changeset).

Другие советы

You can simply decorate the class itself instead of overriding the dispatch method or using a mixin.

For example

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

@method_decorator(cache_page(60 * 5), name='dispatch')
class ListView(ListView):
...

Django docs on decorating a method within a class based view.

yet another good example CacheMixin from cyberdelia github

class CacheMixin(object):
    cache_timeout = 60

    def get_cache_timeout(self):
        return self.cache_timeout

    def dispatch(self, *args, **kwargs):
        return cache_page(self.get_cache_timeout())(super(CacheMixin, self).dispatch)(*args, **kwargs)

usecase:

from django.views.generic.detail import DetailView


class ArticleView(CacheMixin, DetailView):
    cache_timeout = 90
    template_name = "article_detail.html"
    queryset = Article.objects.articles()
    context_object_name = "article"

You can add it as a class decorator and even add multiple using a list:

@method_decorator([vary_on_cookie, cache_page(900)], name='dispatch')
class SomeClass(View):
   ...

I created this little mixin generator to do the caching in the views file, instead of in the URL conf:

def CachedView(cache_time=60 * 60):
    """
    Mixing generator for caching class-based views.

    Example usage:

    class MyView(CachedView(60), TemplateView):
        ....

    :param cache_time: time to cache the page, in seconds
    :return: a mixin for caching a view for a particular number of seconds
    """
    class CacheMixin(object):
        @classmethod
        def as_view(cls, **initkwargs):
            return cache_page(cache_time)(
                super(CacheMixin, cls).as_view(**initkwargs)
            )
    return CacheMixin

Yet another answer, we found this to be simplest and is specific to template views.

class CachedTemplateView(TemplateView):
    @classonlymethod
    def as_view(cls, **initkwargs): #@NoSelf
        return cache_page(15 * 60)(super(CachedTemplateView, cls).as_view(**initkwargs))

I didn't found a good cache solution for class based views and created my own: https://gist.github.com/svetlyak40wt/11126018

It is a mixin for a class. Add it before the main base class and implement method get_cache_params like that:

def get_cache_params(self, *args, **kwargs):
   return ('some-prefix-{username}'.format(
       username=self.request.user.username),
            3600)

Would like to add this: If you need to use multiple decorators for cache like vary_on_headers and cache_page together, here is one way I did:

class CacheHeaderMixin(object):
    cache_timeout = int(config('CACHE_TIMEOUT', default=300))

def get_cache_timeout(self):
    return self.cache_timeout

def dispatch(self, *args, **kwargs):
    return vary_on_headers('Authorization')(cache_page(self.get_cache_timeout())(super(CacheHeaderMixin, self).dispatch))(*args, **kwargs)

This way cache is stored and it varies for different Authorization header (JWT). You may use like this for a class based view.

class UserListAPIView(CacheHeaderMixin, ListAPIView):
    serializer_class = UserSerializer
    def get_queryset(self):
        return CustomUser.objects.all()

Here's my variation of the CachedView() mixin - I don't want to cache the view if the user is authenticated, because their view of pages will be unique to them (e.g. include their username, log-out link, etc).

class CacheMixin(object):
    """
    Add this mixin to a view to cache it.

    Disables caching for logged-in users.
    """
    cache_timeout = 60 * 5 # seconds

    def get_cache_timeout(self):
        return self.cache_timeout

    def dispatch(self, *args, **kwargs):
        if hasattr(self.request, 'user') and self.request.user.is_authenticated:
            # Logged-in, return the page without caching.
            return super().dispatch(*args, **kwargs)
        else:
            # Unauthenticated user; use caching.
            return cache_page(self.get_cache_timeout())(super().dispatch)(*args, **kwargs)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top