-
-
Save douglasgoodwin/377354 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
from django.db.models.query import QuerySet | |
from django.core.cache import cache | |
from django.db import models | |
import random | |
# douglas goodwin 4/2010 | |
# eculver's code with a couple of fixes and instructions | |
# | |
# maybe not the nest way to do it but... | |
# | |
# paste this into a file called cachemanager.py on your django path | |
# in your models.py file: | |
# | |
# from cachemanager import CacheManager | |
# | |
# then: | |
# Class BlahBlah(models.Model): | |
# ... | |
# objects = CacheManager() | |
# | |
# then, in your views.py the usual business: | |
# allblahblah = BlahBlah.objects.all() | |
class CacheManager(models.Manager): | |
def _test_mymodel(obj, *args): | |
''' 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. | |
NOTE: changed method name to avoid namespace collision (DGOODWIN 7/2010) | |
NOTE: Added *args to trap instances where too many args have been passed (DGOODWIN 7/2010) | |
''' | |
# Duct tape way to make the conditionals work | |
if len(args) > 0: | |
return False | |
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_mymodel(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