Commit 2c7975f8 by Nimisha Asthagiri

Move cache_toolbox from common to openedx/core.

parent 4bb88109
......@@ -347,7 +347,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',
......
"""
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)
......
"""
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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment