Кэширование страниц только для анонимов

Нет никакого смысла нагружать свою базу данных лишними запросами для отображения страниц своего сайта неавторизированному пользователю, когда есть возможность переиспользовать уже полученное. За исключением случаев, когда концепция вашего веб-ресурса предполагает снабжение всех и вся часто и динамически обновляющейся информацией. Тут, конечно, нужен более интеллектуальный подход. Но такие ресурсы - суть штучный товар. В подавляющем большинстве ситуаций анонимы видят одно и тоже содержимое. Обновляющееся если и не изредка, то уж точно не чаще раза в час.

Для кэширования страниц Django предоставляет нам замечательный декоратор @cache_page. Инвалидацию данных которого я уже описывал ранее. Декоратор, безусловно, полезный, но крайне бедный на возможности. С его помощью мы можем закэшировать нужные страницы, отдаваемые определенными view, для всех наших посетителей без исключения. Какая-либо фильтрация по пользовательским статусам в оном не заложена. Значит надо подложить.

Напишем свой декоратор. Который, используя все тот же @cache_page, позволит применять функционал постраничного кэширования только для анонимных посетителей сайта. Всех, кто зарегистрирован и "представился" это затрагивать не будет.

Декоратор @cache_for_anonymous

Код с новым функционалом поместим в файл decorators.py, который, в моем случае, положен в основную папку проекта (там, где settings.py).

Нам понадобится импортировать:

  • уже упомянутый cache_page - на его основе мы будем создавать свое решение;

  • декоратор wraps из functools, куда без него;

  • декоратор available_attrs из Django`вских django.utils.decorators - для передачи аргументов декорируемого view в wraps;

На вход наш @cache_for_anonymous принимает лишь количество секунд, в течении которых созданный для анонимов кэш будет актуален.

# project_name/decorators.py
from django.views.decorators.cache import cache_page
from functools import wraps
from django.utils.decorators import available_attrs
  
def cache_for_anonymous(timeout=3600):
    ''' 
    Декоратор для view, кэширующий страницы только для·
    анонимных пользователей.
    '''
    def decorator(view):
        @wraps(view, assigned=available_attrs(view))
        def _wrapped(request, *args, **kwargs):
            if request.user.is_authenticated():
                return (view)(request, *args, **kwargs)
            else:
                return cache_page(timeout)(view)(request, *args, **kwargs) 
        return _wrapped
    return decorator 

Примеры использования

После создания декоратора мы может его использовать точно так же, как и @cache_page.

В urls.py

# project_name/urls.py
...
from some_app import view
from project_name.decorators import cache_for_anonymous
  
urlpatterns = [
    url(r'^articles/list/$', 
        # Кэшируем страницу на пол часа.
        cache_for_anonymous(1800)(views.ArticleList.as_view()), 
                              name='articles-list'),
        ...
    ]


В views.py

# some_app/views.py
...
from django.views.generic import ListView
from project_name.decorators import cache_for_anonymous
  
@cache_for_anonymous(1800)
def article_some_page(request):
    ...
  
   
class ArticleList(ListView):
    ...
    @method_decorator(cache_for_anonymous(1800))
    def get(self, request, *args, **kwargs):
        ...