Django per user view caching

前端 未结 4 956
孤街浪徒
孤街浪徒 2020-12-14 13:10

I need a per user caching. The regular view caching does unfortunately not support user-based caching.

I tried the template fragment caching like this:



        
相关标签:
4条回答
  • 2020-12-14 13:35

    For people using django rest framework and maybe others:

    def cache_per_user(timeout):
      def decorator(view_func):
        @wraps(view_func, assigned=available_attrs(view_func))
        def _wrapped_view(request, *args, **kwargs):
            user_id = 'not_auth'
            if request.user.is_authenticated:
                user_id = request.user.id
    
            return cache_page(timeout, key_prefix="_user_{}_".format(user_id))(view_func)(request, *args, **kwargs)
    
        return _wrapped_view
    
      return decorator
    

    Usage:

    @method_decorator(cache_per_user(3600))
    
    0 讨论(0)
  • 2020-12-14 13:37

    The following is an improved version for the accepted solution does not consider the request parameters.

    decorator_of_cache_per_user.py

    from django.core.cache import cache as core_cache
    
    def cache_key(request):
        if request.user.is_anonymous():
            user = 'anonymous'
        else:
            user = request.user.id
    
        q = getattr(request, request.method)
        q.lists()
        urlencode = q.urlencode(safe='()')
    
        CACHE_KEY = 'view_cache_%s_%s_%s' % (request.path, user, urlencode)
        return CACHE_KEY
    
    def cache_per_user_function(ttl=None, prefix=None, cache_post=False):
        def decorator(function):
            def apply_cache(request, *args, **kwargs):
                CACHE_KEY = cache_key(request)
    
                if prefix:
                    CACHE_KEY = '%s_%s' % (prefix, CACHE_KEY)
    
                if not cache_post and request.method == 'POST':
                    can_cache = False
                else:
                    can_cache = True
    
                if can_cache:
                    response = core_cache.get(CACHE_KEY, None)
                else:
                    response = None
    
                if not response:
                    response = function(request, *args, **kwargs)
                    if can_cache:
                        core_cache.set(CACHE_KEY, response, ttl)
                return response
            return apply_cache
        return decorator
    
    0 讨论(0)
  • 2020-12-14 13:46

    As of Django >=1.7, using the cache_page along with vary_on_cookie decorators on your view should solve this.

    Something like this:

    from django.views.decorators.vary import vary_on_cookie
    from django.views.decorators.cache import cache_page
    
    @cache_page(60 * 15)
    @vary_on_cookie
    def view_to_cache(request):
        ...
    

    Take note of the order of decorators as vary_on_cookie should be processed before it gets to cache_page.

    0 讨论(0)
  • 2020-12-14 13:55

    I found the solution!

    Here is this Portuguese code snippet which works like a charm!

    The good thing is that I don't need to fiddle around my template code but can use a clean decorator!

    Code is included below

    # -*- encoding: utf-8 -*-
    '''
    Python >= 2.4
    Django >= 1.0
    
    Author: eu@rafaelsdm.com
    '''
    from django.core.cache import cache
    
    def cache_per_user(ttl=None, prefix=None, cache_post=False):
        '''Decorador que faz cache da view pra cada usuario
        * ttl - Tempo de vida do cache, não enviar esse parametro significa que o
          cache vai durar até que o servidor reinicie ou decida remove-lo 
        * prefix - Prefixo a ser usado para armazenar o response no cache. Caso nao
          seja informado sera usado 'view_cache_'+function.__name__
        * cache_post - Informa se eh pra fazer cache de requisicoes POST
        * O cache para usuarios anonimos é compartilhado com todos
        * A chave do cache será uma das possiveis opcoes:
            '%s_%s'%(prefix, user.id)
            '%s_anonymous'%(prefix)
            'view_cache_%s_%s'%(function.__name__, user.id)
            'view_cache_%s_anonymous'%(function.__name__)
        '''
        def decorator(function):
            def apply_cache(request, *args, **kwargs):
                # Gera a parte do usuario que ficara na chave do cache
                if request.user.is_anonymous():
                    user = 'anonymous'
                else:
                    user = request.user.id
    
                # Gera a chave do cache
                if prefix:
                    CACHE_KEY = '%s_%s'%(prefix, user)
                else:
                    CACHE_KEY = 'view_cache_%s_%s'%(function.__name__, user)       
    
                # Verifica se pode fazer o cache do request
                if not cache_post and request.method == 'POST':
                    can_cache = False
                else:
                    can_cache = True
    
                if can_cache:
                    response = cache.get(CACHE_KEY, None)
                else:
                    response = None
    
                if not response:
                    response = function(request, *args, **kwargs)
                    if can_cache:
                        cache.set(CACHE_KEY, response, ttl)
                return response
            return apply_cache
        return decorator
    
    0 讨论(0)
提交回复
热议问题