5π
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
32π
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
.
- Profiling Django webserver for high startup times
- Django F expression on datetime objects
- Django abstract parent model save overriding
5π
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))
2π
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π
in this version i include in the cache key the different *args and **kwargs based on the accepted answer
def cache_per_user(ttl=None, prefix=None, cache_post=False):
'''Decorator that caches the view for each user
* ttl - Cache lifetime, not sending this parameter means the
cache will last until the server restarts or decides to remove it
* prefix - Prefix to be used to cache the response. if not
be informed will use 'view_cache_'+function.__name__
* cache_post - Informs whether to cache POST requests
* Cache for anonymous users is shared with everyone
* The cache key will be one of the possible options:
'%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):
if request.user.is_anonymous():
user = 'anonymous'
else:
user = request.user.id
if prefix:
base_key = '%s_%s' % (prefix, user)
else:
base_key = 'view_cache_%s_%s' % (function.__name__, user)
# Include function arguments in the cache key
args_key = '_'.join([str(arg) for arg in args])
# Include keyword arguments in the cache key
kwargs_key = '_'.join(['%s=%s' % (key, value) for key, value in kwargs.items()])
# Generate the cache key
CACHE_KEY = '%s_%s_%s' % (base_key, args_key, kwargs_key)
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