How to cache SQL Alchemy calls with Flask-Cache and Redis?

23,751

Solution 1

You don't need to create custom RedisCache class. The docs is just teaching how you would create new backends that are not available in flask-cache. But RedisCache is already available in werkzeug >= 0.7, which you might have already installed because it is one of the core dependencies of flask.

This is how I could run the flask-cache with redis backend:

import time
from flask import Flask
from flask_cache import Cache

app = Flask(__name__)
cache = Cache(app, config={'CACHE_TYPE': 'redis'})

@cache.memoize(timeout=60)
def query_db():
    time.sleep(5)
    return "Results from DB"

@app.route('/')
def index():
    return query_db()

app.run(debug=True)

The reason you're getting "ImportError: redis is not a valid FlaskCache backend" is probably because you don't have redis (python library) installed which you can simply install by:
pip install redis.

Solution 2

your redis args would look something like this:

cache = Cache(app, config={
    'CACHE_TYPE': 'redis',
    'CACHE_KEY_PREFIX': 'fcache',
    'CACHE_REDIS_HOST': 'localhost',
    'CACHE_REDIS_PORT': '6379',
    'CACHE_REDIS_URL': 'redis://localhost:6379'
    })

Putting the @cache.memoize over a method that grabs the info from the DB should work.

Share:
23,751

Related videos on Youtube

bernie2436
Author by

bernie2436

Updated on April 02, 2020

Comments

  • bernie2436
    bernie2436 about 4 years

    I have a Flask app that takes parameters from a web form, queries a DB with SQL Alchemy and returns Jinja-generated HTML showing a table with the results. I want to cache the calls to the DB. I looked into Redis (Using redis as an LRU cache for postgres), which led me to http://pythonhosted.org/Flask-Cache/.

    Now I am trying to use Redis + Flask-Cache to cache the calls to the DB. Based on the Flask-Cache docs, it seems like I need to set up a custom Redis cache.

    class RedisCache(BaseCache):
        def __init__(self, servers, default_timeout=500):
            pass
    
    def redis(app, config, args, kwargs):
       args.append(app.config['REDIS_SERVERS'])
       return RedisCache(*args, **kwargs)
    

    From there I would need to something like:

    # not sure what to put for args or kwargs
    cache = redis(app, config={'CACHE_TYPE': 'redis'})
    
    app = Flask(__name__)
    cache.init_app(app)
    

    I have two questions:

    1. What do I put for args and kwargs? What do these mean? How do I set up a Redis cache with Flask-Cache?

    2. Once the cache is set up, it seems like I would want to somehow "memoize" the calls the DB so that if the method gets the same query it has the output cached. How do I do this? My best guess would be to wrap the call the SQL Alchemy in a method that could then be given memoize decorator? That way if two identical queries were passed to the method, Flask-Cache would recognize this and return to the appropriate response. I'm guessing that it would look like this:

      @cache.memoize(timeout=50)
      def queryDB(q):
          return q.all()
      

    This seems like a fairly common use of Redis + Flask + Flask-Cache + SQL Alchemy, but I am unable to find a complete example to follow. If someone could post one, that would be super helpful -- but for me and for others down the line.

    • ezdazuzena
      ezdazuzena over 9 years
      I encountered the problem that passing a query object as argument yielded memoize using the object's memory address. A wrapping class solved this for. Hope this might help somebody..
  • bernie2436
    bernie2436 almost 10 years
    If I follow this example, I get "ImportError: redis is not a valid FlaskCache backend"
  • bernie2436
    bernie2436 almost 10 years
    If I change CACHE_TYPE to 'redis' I get ERROR:flask_cache:Exception possibly due to cache backend....AttributeError: 'Flask' object has no attribute 'mget'
  • Riz
    Riz almost 10 years
    Make sure you have the redid python library installed. pip install redis
  • Ctrl-C
    Ctrl-C about 7 years
    pip install redis in my case :) Remember that you need to configure redis connection like Riz described in his answer.
  • Ronnie Beltran
    Ronnie Beltran almost 7 years
    Note: Importing flask extension using from flask flaskt.ext.cache import Cache has been deprecated use: from flask_cache import Cache instead.
  • nenur
    nenur about 4 years
    How do you set up a Redis host for production (not using localhost as the host)? I'm trying to find a good online guide to get the Redis host set up but can't find anything.