In Django, how can create a single cached version of a page (same for all users) that's only visible to authenticated users?
The pages I wish to cache are only available to authenticated users (they use @login_required
on the view). These pages are the same for all authenticated users (e.g. no need to setup vary_on_headers
based on unique users).
However, I don't want these cached pages to be visible to non-authenticated users.
vary_on_headers
, but I don't need individually cached pages for each userThanks!
@login_required @cache_page(60 * 60) def index(request): '''Display the home page''' return render(request, 'index.html')
# Add the below for memcache MIDDLEWARE_CLASSES += ( 'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.cache.FetchFromCacheMiddleware', ) # Enable memcache # https://devcenter.heroku.com/articles/memcache#using_memcache_from_python CACHES = { 'default': { 'BACKEND': 'django_pylibmc.memcached.PyLibMCCache' } }
Based on the answer by @Tisho I solved this problem by
decorators.py
file in my appviews.py
from functools import wraps from django.views.decorators.cache import cache_page from django.utils.decorators import available_attrs def cache_on_auth(timeout): def decorator(view_func): @wraps(view_func, assigned=available_attrs(view_func)) def _wrapped_view(request, *args, **kwargs): if request.user.is_authenticated(): return cache_page(timeout)(view_func)(request, *args, **kwargs) else: return view_func(request, *args, **kwargs) return _wrapped_view return decorator
For logged in users, it would cache the page (or serve them the cached page) for non-logged in users, it would just give them the regular view, which was decorated with @login_required
and would require them to login.
Django also works well with “downstream” caches, such as Squid and browser-based caches. These are the types of caches that you don't directly control but to which you can provide hints (via HTTP headers) about which parts of your site should be cached, and how.
Memcached. This is the most efficient caching system supported natively in Django. Memcached provides a fast interface for adding, retrieving, and deleting data from the cache. Here, all data are stored directly in memory instead of the database, which makes accessing the data faster.
Local Memory Cache Unless we explicitly specify another caching method in our settings file, Django defaults to local memory caching. As its name implies, this method stores cached data in RAM on the machine where Django is running. Local memory caching is fast, responsive, and thread-safe.
To use cache in Django, first thing to do is to set up where the cache will stay. The cache framework offers different possibilities - cache can be saved in database, on file system or directly in memory. Setting is done in the settings.py file of your project.
The default cache_page
decorator accepts a variable called key_prefix
. However, it can be passed as a string parameter only. So you can write your own decorator, that will dynamically modify this prefix_key
based on the is_authenticated
value. Here is an example:
from django.views.decorators.cache import cache_page def cache_on_auth(timeout): def decorator(view_func): @wraps(view_func, assigned=available_attrs(view_func)) def _wrapped_view(request, *args, **kwargs): return cache_page(timeout, key_prefix="_auth_%s_" % request.user.is_authenticated())(view_func)(request, *args, **kwargs) return _wrapped_view return decorator
and then use it on the view:
@cache_on_auth(60*60) def myview(request)
Then, the generated cache_key will look like:
cache key: views.decorators.cache.cache_page._auth_False_.GET.123456.123456
if the user is authenticated, and
cache key: views.decorators.cache.cache_page._auth_True_.GET.789012.789012
if the user is not authenticated.
If the @wrap decorator in the @Tisho answer makes your brain hurt, or if an explicit solution is better than an implicit one, here's a simple procedural way to serve different cache results:
from django.views.decorators.cache import cache_page def index(request): """ :type request: HttpRequest """ is_authenticated = request.user.is_authenticated() if is_authenticated: return render_user(request) else: return render_visitor(request) @cache_page(5, key_prefix='user_cache') def render_user(request): print 'refreshing user_cache' return render(request, 'home-user.html', {}) @cache_page(10, key_prefix='visitor_cache') def render_visitor(request): print 'refreshing visitor_cache' return render(request, 'home-visitor.html', {})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With