He utilizado UpdateCacheMiddleware
y FetchFromCacheMiddleware
MiddleWare para habilitar el almacenamiento en caché anónimo en todo el sitio con distintos niveles de éxito.Técnica para crear subclase Django UpdateCacheMiddleware y FetchFromCacheMiddleware
El mayor problema es que el middleware solo almacena en caché la primera solicitud de un usuario anónimo. Como una cookie session_id se establece en esa primera respuesta, las solicitudes posteriores de ese usuario anónimo no presionan la caché como resultado de la caché de nivel de vista que varía en los encabezados.
Mis páginas web no varían significativamente entre los usuarios anónimos y, en la medida en que varían, puedo manejar eso a través de Ajax. Como resultado, decidí tratar de subclavar el middleware de caché de Django para que no varíe en Header. En cambio, varía en usuarios anónimos y usuarios conectados. Debido a que estoy usando el back-end de Auth, y ese controlador ocurre antes de ir a la caché, parece funcionar.
class AnonymousUpdateCacheMiddleware(UpdateCacheMiddleware):
def process_response(self, request, response):
"""
Sets the cache, if needed.
We are overriding it in order to change the behavior of learn_cache_key().
"""
if not self._should_update_cache(request, response):
# We don't need to update the cache, just return.
return response
if not response.status_code == 200:
return response
timeout = get_max_age(response)
if timeout == None:
timeout = self.cache_timeout
elif timeout == 0:
# max-age was set to 0, don't bother caching.
return response
patch_response_headers(response, timeout)
if timeout:
######### HERE IS WHERE IT REALLY GOES DOWN #######
cache_key = self.learn_cache_key(request, response, self.cache_timeout, self.key_prefix, cache=self.cache)
if hasattr(response, 'render') and callable(response.render):
response.add_post_render_callback(
lambda r: self.cache.set(cache_key, r, timeout)
)
else:
self.cache.set(cache_key, response, timeout)
return response
def learn_cache_key(self, request, response, timeout, key_prefix, cache=None):
"""_generate_cache_header_key() creates a key for the given request path, adjusted for locales.
With this key, a new cache key is set via _generate_cache_key() for the HttpResponse
The subsequent anonymous request to this path hits the FetchFromCacheMiddleware in the
request capturing phase, which then looks up the headerlist value cached here on the initial response.
FetchFromMiddleWare calcuates a cache_key based on the values of the listed headers using _generate_cache_key
and then looks for the response stored under that key. If the headers are the same as those
set here, there will be a cache hit and the cached HTTPResponse is returned.
"""
key_prefix = key_prefix or settings.CACHE_MIDDLEWARE_KEY_PREFIX
cache_timeout = self.cache_timeout or settings.CACHE_MIDDLEWARE_SECONDS
cache = cache or get_cache(settings.CACHE_MIDDLEWARE_ALIAS)
cache_key = _generate_cache_header_key(key_prefix, request)
# Django normally varies caching by headers so that authed/anonymous users do not see same pages
# This makes Google Analytics cookies break caching;
# It also means that different anonymous session_ids break caching, so only first anon request works
# In this subclass, we are ignoring headers and instead varying on authed vs. anonymous users
# Alternatively, we could also strip cookies potentially for the same outcome
# if response.has_header('Vary'):
# headerlist = ['HTTP_' + header.upper().replace('-', '_')
# for header in cc_delim_re.split(response['Vary'])]
# else:
headerlist = []
cache.set(cache_key, headerlist, cache_timeout)
return _generate_cache_key(request, request.method, headerlist, key_prefix)
La obtención de mensajes, el cual es responsable de recuperar la página de la caché, se parece a esto
class AnonymousFetchFromCacheMiddleware(FetchFromCacheMiddleware):
def process_request(self, request):
"""
Checks whether the page is already cached and returns the cached
version if available.
"""
if request.user.is_authenticated():
request._cache_update_cache = False
return None
else:
return super(SmarterFetchFromCacheMiddleware, self).process_request(request)
Hubo una gran cantidad de copias de UpdateCacheMiddleware
, obviamente. No pude encontrar un gancho mejor para hacer esto más limpio.
¿Esto generalmente parece un buen enfoque? ¿Alguna pregunta obvia que se te ocurra?
Gracias, Ben
Hola okm, mi implementación efectivamente lo hace, ¿verdad? – Ben
@Ben No hay gran diferencia. Pero comparando w/código duplicado, prefiero la herencia aquí. Está más claro, tiene menos código en tu proyecto y causaría menos dolores de cabeza cuando actualices la versión de Django – okm
gracias okm, todos puntos buenos – Ben