I'm trying to use a Memcached instance of AWS ElastiCache with a Django project. It seems to be caching a view for a user, but if you come in on a different PC, it isn't cached until called from that PC (or same PC with different browser).
I'm not sure what I've got wrong.
Within settings.py I have
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': os.environ.get('CACHE_LOCATION','127.0.0.1:11211'),
}
}
MIDDLEWARE = [
'core.middleware.DenyIndexMiddleware',
'core.middleware.XForwardedForMiddleware',
'core.middleware.PrimaryHostRedirectMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
'masquerade.middleware.MasqueradeMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.contrib.sites.middleware.CurrentSiteMiddleware',
'cms.middleware.user.CurrentUserMiddleware',
'cms.middleware.page.CurrentPageMiddleware',
'cms.middleware.toolbar.ToolbarMiddleware',
'cms.middleware.language.LanguageCookieMiddleware',
'cms.middleware.utils.ApphookReloadMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
]
I've then cached the views using cache_page
path('<str:service_type>/<str:location>/', cache_page(60*60)(views.canonical_search), name="canonical-search"),
How do I cache the site so that the page is cached irrespective of the user?
EDIT
I've noticed that it never caches when using the user is logged in.
Watch out for the Vary header, that cache_page() takes into account.
Usually, some middlewares may add a Vary header, for example :
CsrfViewMiddleware adds Cookie,
GZipMiddlewareadds Accept-Encoding
LanguageCookieMiddleware may add Accept-Language
meaning that as soon as you have a different Cookie (session), encoding, or language, you have a different version of cache for your page.
As for you case, the CsrfViewMiddleware may be the problem, you can add the decorator #csrf_exempt to your view so that the Vary: Cookie header is not set in the response.
More info at https://docs.djangoproject.com/en/3.0/topics/cache/#using-vary-headers
Though Django documentation, you can read this:
Django’s cache framework
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
If you need to store a page in the local
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': 'c:/foo/bar',
}
}
But, my recommendation is store the results (database result, assets, etc), as #PVSK show in this thread:
from django.core.cache import cache
def sample(request):
cached_data = cache.get_many(['query1', 'query2'])
if cached_data:
return render(request, 'sample.html', {'query1': cached_data['query1'], 'query2': cached_data['query2']})
else:
queryset1 = Model.objects.all()
queryset2 = Model2.objects.all()
cache.set_many({'query1': queryset1 , 'query2': queryset2 }, None)
return render(request, 'sample.html', {'query1': queryset1 , 'query2': queryset2})
Hm, at first I wondered if you're running into some cache default limitations. You are not using OPTIONS in your CACHE backend definition, so the cache is limited to 300 entries per default.
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': os.environ.get('CACHE_LOCATION','127.0.0.1:11211'),
'OPTIONS': {
'MAX_ENTRIES': 1000
}
}
}
The next possible problem, that we also had, is that the cache_key generation takes the full QUERY_STRING into account, so (the ?param=bla). But you already stated that the url is the same for all users.
Next up, as SebCorbin correctly identified, are the potential Vary issues.
UpdateCacheMiddleware will never cache a cookie-setting response to a cookie-less request.
def process_response(self, request, response):
#...
# Don't cache responses that set a user-specific (and maybe security
# sensitive) cookie in response to a cookie-less request.
if not request.COOKIES and response.cookies and has_vary_header(response, 'Cookie'):
return response
# ...
The order of execution of middlewares is top-to-bottom for process_request and bottom-to-top for process_response.
I suspect that one of lower middlewares (or the view) is setting a cookie, so you might be able to work around this issue by moving the 'django.middleware.cache.UpdateCacheMiddleware' below the offending middleware, but you risk loosing features if you don't move feature-middlewares like LocaleMiddleware as well.
If your view code is setting cookies you'll need to switch to the low-level cache API to cache costly operations (or move the cookie logic into a middleware that lives above the UpdateCacheMiddleware middleware).
I'm using template cache with django-redis and it works properly but, although I don't use decorators (like cache_page, cache_control etc..), django is caching automatically every loaded page.
I verified this using redis-cli. This is keys * output after page load:
1) ":1:views.decorators.cache.cache_header..11786bb66822aef24b9fe0dac22e6e4e..."
2) ":1:views.decorators.cache.cache_page..GET.11786bb66822aef24b9fe0dac22e6e4e..."
3) ":1:django.contrib.sessions.cached_db8ss2k5s9jmp42cer0fs1nd..."
I tried to use never_cache on every view and it works but I don't see that as a good solution.
There's a better way?
My configuration is simple
CACHES = {
'default':
{
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://redis_ip:redis_port',
'TIMEOUT': 60
},
}
MIDDLEWARE.PY
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
...
'django.middleware.cache.FetchFromCacheMiddleware',
...]
Thanks to all
Remove UpdateCacheMiddleware and FetchFromCacheMiddleware from your MIDDLEWARE settings. They are meant for per-site caching, so every page is cached when you have those middleware.
I am trying to integrate filebased session in django. I have followed all the provided details But session is not working.
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
}
}
I am getting below error
Exception Type: OperationalError
Exception Value:
no such table: django_session
Looks like you confused caching and session frameworks. Your current settings is affecting only cache system. To use file based session you need to add SESSION_ENGINE and SESSION_FILE_PATH settings:
SESSION_ENGINE = "django.contrib.sessions.backends.file"
SESSION_FILE_PATH = "/var/tmp/django_cache"
We are trying to implement caching in Django. We have tried memcache, file system caching and local memory caching. No mater what it just isn't working -- a timestamp we put on the template to test caching is always updating so we know it's not working.
Here are relevant portions of code.
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': 'c:/tmp',
}
}
CACHE_MIDDLEWARE_ALIAS = "default"
CACHE_MIDDLEWARE_SECONDS = 600
MIDDLEWARE_CLASSES = [
"django.middleware.cache.UpdateCacheMiddleware",
... OTHER ONES ...
"django.middleware.cache.FetchFromCacheMiddleware",
]
VIEWS.PY
from django.views.decorators.cache import cache_page
#cache_page(60 * 10)
def profiles(request, template_name="profiles/profiles.html", extra_context=None):
...
Default django cache keys generator:
def make_key(key, key_prefix, version):
return ':'.join([key_prefix, str(version), key])
I want to change with:
in settings.py
def make_key(key, key_prefix, version):
return key
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
'KEY_FUNCTION' : 'settings.make_key',
}
}
but django generate keys with old native function (prefix-version-key) how to change it?
Try:
def make_key(key, key_prefix, version):
return key
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
'KEY_FUNCTION' : make_key
}
}
I know that in documentation is "string containing a dotted path" but I see in the Django source code that you can also pass callable object (eg. function).
If you really need to pass it as a string, you should move this function to another module and set yourproject.module.make_key as KEY_FUNCTION.