Search code examples
pythondjangomemoizationdjango-managers

django: how to memoize model manager methods?


I have a memoized Django model manager method as follows:

class GroupManager(models.Manager):
    def get_for_user(self, user):
        cache_key = 'groups_%s' % (user.id)
        if not hasattr(self, key):
            groups = get_groups_somehow()
            setattr(self, cache_key, groups)
        return getattr(self, cache_key)

But the memoized value persists beyond the request / response cycle; i.e. the value is not re-calculated in the subsequent requests until the server is restarted. This must be because the manager instance is not destroyed.

So, how can I properly memoize model manager methods?


Solution

  • with inspiration from https://stackoverflow.com/a/1526245/287923, but simplifying it, i've implemented a request cache as follows:

    from threading import currentThread
    
    caches = {}
    
    class RequestCache(object):
        def set(self, key, value):
            cache_id = hash(currentThread())
            if caches.get(cache_id):
                caches[cache_id][key] = value
            else:
                caches[cache_id] = {key: value}
    
        def get(self, key):
            cache_id = hash(currentThread())
            cache = caches.get(cache_id)
            if cache:
                return cache.get(key)
            return None
    
    class RequestCacheMiddleware(object):
        def process_response(self, request, response):
            cache_id = hash(currentThread())
            if caches.get(cache_id):
                del(caches[cache_id])
            return response
    

    caches is a dictionary of cache dictionaries, accessed via get & set methods. a middleware clears the cache for the current thread in process_response method, after the response is rendered.

    it is used like this:

    from request_cache import RequestCache
    cache = RequestCache()
    cache.get(key)
    cache.set(key, value)