Created
April 20, 2010 17:55
-
-
Save eculver/372823 to your computer and use it in GitHub Desktop.
A generic cache manager
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import random | |
from django.db import models | |
from django.core.cache import cache | |
class CacheManager(models.Manager): | |
'''Generic Cache Manager based on the concept of generator ids to | |
handle invalidation of collections. | |
''' | |
def _test_model(self, obj): | |
''' Checks to see if the current object is up-to-date with it's model. | |
Returns True if it is, otherwise False. | |
Used to tell if an object fetched from cache is fresh. | |
''' | |
# Duct tape way to make the conditionals work | |
if obj is None: | |
return False | |
# Compares the object to a blank version of the model | |
res = dir(obj)==dir(obj.__class__()) | |
return res | |
def _get_model_string(self): | |
''' Return the correct string for a given model. ''' | |
return self.model.__name__.lower() | |
def _get_generator_id(self): | |
''' Return the generator id for a given model. | |
This is used for getting and invalidating collections. | |
<model_name>-generator_id -> generator_id | |
<model_name>-<generator_id> -> <collection> | |
On save, save new generator id, auto-invalidates all collections. | |
Generator id is just a random 5-digit number. | |
''' | |
key = "%s-generator_id" % self._get_model_string() | |
generator_id = cache.get(key) | |
if not generator_id: | |
cache.set(key, int(random.random() * 100000), 60 * 60 * 48) # 48 hours. | |
return generator_id | |
def get(self, **kwargs): | |
''' Return the object by id. Sets it into cache. If no object is | |
found, returns None. | |
''' | |
key = self._get_model_string() | |
for k,v in kwargs.iteritems(): | |
key = "%s:%s:%s" % (key, k, v) | |
object = cache.get(key) | |
if not object or not self._test_model(object): | |
try: | |
object = super(CacheManager, self).get(**kwargs) | |
cache.set(key, object, 60 * 60 * 24) | |
except self.model.DoesNotExist: | |
object = None | |
return object | |
def filter(self, **kwargs): | |
''' Try to get a bunch of objects from cache. | |
Uses generator_id and signals to make sure that it's getting the | |
most up to date collection. On save, a new generator_id is | |
generated. | |
''' | |
key = "%s-%s" % (self._get_model_string(), self._get_generator_id()) | |
for k,v in kwargs.iteritems(): | |
key = "%s:%s:%s" % (key, k, v) | |
objects = cache.get(key) | |
if not objects: | |
objects = super(CacheManager, self).filter(**kwargs) | |
cache.set(key, objects) | |
return objects | |
def all(self): | |
''' Try to get all objects from cache. ''' | |
key = "%s:all" % self._get_model_string() | |
objects = cache.get(key) | |
if not objects: | |
objects = super(CacheManager, self).all() | |
cache.set(key, objects) | |
return objects |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment