import inspect from django.core.cache import cache class ModelProxy(object): def __init__(self, model, expiration, prefix=None): self._model = model self._expiration = expiration self._await = False self._path = [] self._prefix = None def __getattr__(self, name): if name == 'objects' or self._await: self._path.append(name) self._await = True return self return getattr(self._model, name) def __call__(self, *args, **kwargs): hash = (args).__hash__() if self._prefix: hash = self._prefix + hash result = cache.get(hash) if not result: parcial = self.__dict__['_model'] for bit in self._path: parcial = getattr(parcial, bit) result = parcial(*args, **kwargs) cache.set(hash, result, self._expiration) self._await = False self._path = [] return result import functools def cache_holding(object_cache, time_expiration, proxy=ModelProxy, prefix=None): def caller(func): @functools.wraps(func) def wrapper(*args, **kwargs): classnames = object_cache if not hasattr(classnames, '__iter__'): classnames = (classnames,) classnames = [class_.__name__ for class_ in classnames] try: frame = inspect.currentframe() for classname in classnames: if frame.f_globals.has_key(classname): old_class = frame.f_globals.get(classname) frame.f_globals[classname] = proxy(old_class, time_expiration, prefix=prefix) result = func(*args, **kwargs) finally: del frame return result return wrapper return caller from django.contrib.contenttypes.models import ContentType from django.contrib.auth.models import User @cache_holding((ContentType, User), 100) def test(): from django.db import connection connection.queries = [] a = ContentType.objects.all() b = ContentType.objects.all() print a,b, connection.queries print User.news_related.all() def do_test(n): for x in xrange(n): print "Num: %d" % x, test()