Merge pull request #13673 from edx/common_cleanup/cache_toolbox
Move cache_toolbox from common to openedx/core
This commit is contained in:
@@ -348,7 +348,7 @@ MIDDLEWARE_CLASSES = (
|
||||
'method_override.middleware.MethodOverrideMiddleware',
|
||||
|
||||
# Instead of AuthenticationMiddleware, we use a cache-backed version
|
||||
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
|
||||
'openedx.core.djangoapps.cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
|
||||
# Enable SessionAuthenticationMiddleware in order to invalidate
|
||||
# user sessions after a password change.
|
||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||
|
||||
@@ -1098,7 +1098,7 @@ MIDDLEWARE_CLASSES = (
|
||||
|
||||
# Instead of AuthenticationMiddleware, we use a cached backed version
|
||||
#'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
|
||||
'openedx.core.djangoapps.cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
|
||||
# Enable SessionAuthenticationMiddleware in order to invalidate
|
||||
# user sessions after a password change.
|
||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
"""
|
||||
Settings for cache_toolbox.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
# Default cache timeout
|
||||
@@ -34,40 +34,36 @@ def get_instance(model, instance_or_pk, timeout=None, using=None):
|
||||
True
|
||||
|
||||
"""
|
||||
pk = getattr(instance_or_pk, 'pk', instance_or_pk)
|
||||
primary_key = getattr(instance_or_pk, 'pk', instance_or_pk)
|
||||
key = instance_key(model, instance_or_pk)
|
||||
data = cache.get(key)
|
||||
|
||||
if data is not None:
|
||||
try:
|
||||
# Try and construct instance from dictionary
|
||||
instance = model(pk=pk, **data)
|
||||
instance = model(pk=primary_key, **data)
|
||||
|
||||
# Ensure instance knows that it already exists in the database,
|
||||
# otherwise we will fail any uniqueness checks when saving the
|
||||
# instance.
|
||||
instance._state.adding = False
|
||||
instance._state.adding = False # pylint: disable=protected-access
|
||||
|
||||
# Specify database so that instance is setup correctly. We don't
|
||||
# namespace cached objects by their origin database, however.
|
||||
instance._state.db = using or DEFAULT_DB_ALIAS
|
||||
instance._state.db = using or DEFAULT_DB_ALIAS # pylint: disable=protected-access
|
||||
|
||||
return instance
|
||||
except:
|
||||
except: # pylint: disable=bare-except
|
||||
# Error when deserialising - remove from the cache; we will
|
||||
# fallback and return the underlying instance
|
||||
cache.delete(key)
|
||||
|
||||
# Use the default manager so we are never filtered by a .get_queryset()
|
||||
|
||||
# import logging
|
||||
# log = logging.getLogger("tracking")
|
||||
# log.info( str(pk) )
|
||||
|
||||
instance = model._default_manager.using(using).get(pk=pk)
|
||||
instance = model._default_manager.using(using).get(pk=primary_key) # pylint: disable=protected-access
|
||||
|
||||
data = {}
|
||||
for field in instance._meta.fields:
|
||||
for field in instance._meta.fields: # pylint: disable=protected-access
|
||||
# Harmless to save, but saves space in the dictionary - we already know
|
||||
# the primary key when we lookup
|
||||
if field.primary_key:
|
||||
@@ -76,8 +72,8 @@ def get_instance(model, instance_or_pk, timeout=None, using=None):
|
||||
if field.get_internal_type() == 'FileField':
|
||||
# Avoid problems with serializing FileFields
|
||||
# by only serializing the file name
|
||||
file = getattr(instance, field.attname)
|
||||
data[field.attname] = file.name
|
||||
file_value = getattr(instance, field.attname)
|
||||
data[field.attname] = file_value.name
|
||||
else:
|
||||
data[field.attname] = getattr(instance, field.attname)
|
||||
|
||||
@@ -67,7 +67,7 @@ with::
|
||||
|
||||
MIDDLEWARE_CLASSES = [
|
||||
...
|
||||
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
|
||||
'openedx.core.djangoapps.cache_toolbox.middleware.CacheBackedAuthenticationMiddleware',
|
||||
...
|
||||
]
|
||||
|
||||
@@ -93,6 +93,9 @@ log = getLogger(__name__)
|
||||
|
||||
|
||||
class CacheBackedAuthenticationMiddleware(AuthenticationMiddleware):
|
||||
"""
|
||||
See documentation above.
|
||||
"""
|
||||
def __init__(self):
|
||||
cache_model(User)
|
||||
|
||||
@@ -110,7 +113,7 @@ class CacheBackedAuthenticationMiddleware(AuthenticationMiddleware):
|
||||
# Raise an exception to fall through to the except clause below.
|
||||
raise Exception
|
||||
self._verify_session_auth(request)
|
||||
except:
|
||||
except: # pylint: disable=bare-except
|
||||
# Fallback to constructing the User from the database.
|
||||
super(CacheBackedAuthenticationMiddleware, self).process_request(request)
|
||||
|
||||
@@ -60,18 +60,28 @@ from .core import get_instance, delete_instance
|
||||
|
||||
|
||||
def cache_model(model, timeout=None):
|
||||
"""
|
||||
Adds utility methods to the given model to obtain
|
||||
``ForeignKey`` instances via the cache.
|
||||
"""
|
||||
if hasattr(model, 'get_cached'):
|
||||
# Already patched
|
||||
return
|
||||
|
||||
def clear_cache(sender, instance, *args, **kwargs):
|
||||
def clear_cache(sender, instance, *args, **kwargs): # pylint: disable=unused-argument
|
||||
"""
|
||||
Clears the cache for the given instance.
|
||||
"""
|
||||
delete_instance(sender, instance)
|
||||
|
||||
post_save.connect(clear_cache, sender=model, weak=False)
|
||||
post_delete.connect(clear_cache, sender=model, weak=False)
|
||||
|
||||
@classmethod
|
||||
def get(cls, pk, using=None):
|
||||
def get(cls, pk, using=None): # pylint: disable=invalid-name
|
||||
"""
|
||||
Returns the model for the given primary key (pk).
|
||||
"""
|
||||
if pk is None:
|
||||
return None
|
||||
return get_instance(cls, pk, timeout, using)
|
||||
@@ -69,18 +69,25 @@ Support
|
||||
``cache_relation`` currently only works with ``OneToOneField`` fields. Support
|
||||
for regular ``ForeignKey`` fields is planned.
|
||||
"""
|
||||
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
|
||||
from .core import get_instance, delete_instance
|
||||
|
||||
|
||||
def cache_relation(descriptor, timeout=None):
|
||||
"""
|
||||
Adds utility methods to a model to obtain related
|
||||
model instances via a cache.
|
||||
"""
|
||||
rel = descriptor.related
|
||||
related_name = '%s_cache' % rel.field.related_query_name()
|
||||
|
||||
@property
|
||||
def get(self):
|
||||
"""
|
||||
Returns the cached value of the related model if found
|
||||
in the cache. Otherwise gets and caches the related model.
|
||||
"""
|
||||
# Always use the cached "real" instance if available
|
||||
try:
|
||||
return getattr(self, descriptor.cache_name)
|
||||
@@ -93,10 +100,6 @@ def cache_relation(descriptor, timeout=None):
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# import logging
|
||||
# log = logging.getLogger("tracking")
|
||||
# log.info( "DEBUG: "+str(str(rel.model)+"/"+str(self.pk) ))
|
||||
|
||||
instance = get_instance(rel.model, self.pk, timeout)
|
||||
|
||||
setattr(self, '_%s_cache' % related_name, instance)
|
||||
@@ -107,13 +110,24 @@ def cache_relation(descriptor, timeout=None):
|
||||
# Clearing cache
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
Clears the cache of all related models of self.
|
||||
"""
|
||||
delete_instance(rel.model, self)
|
||||
|
||||
@classmethod
|
||||
def clear_pk(cls, *instances_or_pk):
|
||||
def clear_pk(cls, *instances_or_pk): # pylint: disable=unused-argument
|
||||
"""
|
||||
Clears the cache of all related models of
|
||||
the provided instances_or_pk.
|
||||
"""
|
||||
delete_instance(rel.model, *instances_or_pk)
|
||||
|
||||
def clear_cache(sender, instance, *args, **kwargs):
|
||||
def clear_cache(sender, instance, *args, **kwargs): # pylint: disable=unused-argument
|
||||
"""
|
||||
Clears the cache of all related models of the
|
||||
given instance.
|
||||
"""
|
||||
delete_instance(rel.model, instance)
|
||||
|
||||
setattr(rel.parent_model, '%s_clear' % related_name, clear)
|
||||
@@ -1,12 +1,21 @@
|
||||
"""
|
||||
Implementation of custom django template tags for
|
||||
automatically caching template fragments.
|
||||
"""
|
||||
from django import template
|
||||
from django.core.cache import cache
|
||||
from django.template import Node, TemplateSyntaxError, Variable
|
||||
from django.template import resolve_variable
|
||||
|
||||
register = template.Library()
|
||||
register = template.Library() # pylint: disable=invalid-name
|
||||
|
||||
|
||||
class CacheNode(Node):
|
||||
"""
|
||||
Subclass of django's template Node class that
|
||||
caches the rendered value of a template fragment. This is a
|
||||
simpler implementation of django.templatetags.cache.CacheNode.
|
||||
"""
|
||||
def __init__(self, nodelist, expire_time, key):
|
||||
self.nodelist = nodelist
|
||||
self.expire_time = Variable(expire_time)
|
||||
@@ -46,6 +55,11 @@ def cachedeterministic(parser, token):
|
||||
|
||||
|
||||
class ShowIfCachedNode(Node):
|
||||
"""
|
||||
Subclass of django's template Node class that
|
||||
renders the cached value for the given key, only
|
||||
if already cached.
|
||||
"""
|
||||
def __init__(self, key):
|
||||
self.key = key
|
||||
|
||||
@@ -55,7 +69,7 @@ class ShowIfCachedNode(Node):
|
||||
|
||||
|
||||
@register.tag
|
||||
def showifcached(parser, token):
|
||||
def showifcached(parser, token): # pylint: disable=unused-argument
|
||||
"""
|
||||
Show content if it exists in the cache, otherwise display nothing.
|
||||
|
||||
Reference in New Issue
Block a user