pythonredisflask-restfulflask-cachecache-invalidation

How to use Flask-Cache with Flask-Restful


How do I use Flask-Cache @cache.cached() decorator with Flask-Restful? For example, I have a class Foo inherited from Resource, and Foo has get, post, put, and delete methods.

How can I can invalidate cached results after a POST?

@api.resource('/whatever')
class Foo(Resource):
    @cache.cached(timeout=10)
    def get(self):
        return expensive_db_operation()

    def post(self):
        update_db_here()

        ## How do I invalidate the value cached in get()?
        return something_useful()

Solution

  • As Flask-Cache implementation doesn't give you access to the underlying cache object, you'll have to explicitly instantiate a Redis client and use it's keys method (list all cache keys).

    This is a solution that was tested only for Redis and the implementation will probably differ a little when using a different cache engine.

    from app import cache # The Flask-Cache object
    from config import CACHE_REDIS_HOST, CACHE_REDIS_PORT # The Flask-Cache config
    from redis import Redis
    from flask import request
    import urllib
    
    redis_client = Redis(CACHE_REDIS_HOST, CACHE_REDIS_PORT)
    
    def cache_key():
       args = request.args
       key = request.path + '?' + urllib.urlencode([
         (k, v) for k in sorted(args) for v in sorted(args.getlist(k))
       ])
       return key
    
    @api.resource('/whatever')
    class Foo(Resource):
    
        @cache.cached(timeout=10, key_prefix=cache_key)
        def get(self):
            return expensive_db_operation()
    
        def post(self):
            update_db_here()
            self.clear_cache()
            return something_useful()
    
        def clear_cache(self):
            # Note: we have to use the Redis client to delete key by prefix,
            # so we can't use the 'cache' Flask extension for this one.
            key_prefix = request.path
            keys = [key for key in redis_client.keys() if key.startswith(key_prefix)]
            nkeys = len(keys)
            for key in keys:
                redis_client.delete(key)
            if nkeys > 0:
                log.info("Cleared %s cache keys" % nkeys)
                log.info(keys)