基本用法
基于 Flask 应用,难免会用到 Flask-cache (或 Flask-cacheing,两者API 基本相同)。它通过装饰器,非常优雅地实现了函数调用的缓存。装饰器可以直接加在 view function ,或者普通 function 上,类似下面的样子:
@app.route('/demo/student/all', methods=['GET'])
@cache.cached(timeout=600)
def get():
students = Student.query.all()
return response_ok(students)
(如果函数有参数,并且希望针对不同实参值,做不同的缓存,那就用 _@cache.memerized _
装饰器)
添加了装饰器的函数,在第一次被调用之后,返回值就被在缓存有效期内,示例中的timeout
参数,保证了缓存在600秒后超时失效,再次调用函数本体获得最新数据。
view function 缓存控制
但有时我们需要控制这个缓存的更新——比如上面的例子中,每次新增一个学生、或者更改学生数据,就重新刷新一下缓存,而不需要等它自然超时。这时就需要显式调用 delete 函数,例如:
del_res = cache.delete('/demo/student/all')
对于 view function 来说,这里 delete 的参数,就恰好等于 route 里的 path,如果 route 来自于一个上级的 blueprint,要记得把上级 path 带上。
如果你要指定 cache 的 key,可以加上 key_prefix 参数,类似下面这样:
@app.route('/demo/student/all', methods=['GET'])
@cache.cached(timeout=600, key_prefix='res_student_all')
def get():
...
注意第一个坑来了:因为名字里有个 prefix,你可能会觉得它是 key 的前缀,删除的时候,会想着怎么组合一下这个参数和 path;然而实际上却不用任何组合,path 在这里已经无效了,删除时直接用这个 key_prefix 当参数就可以:
del_res = cache.delete('res_student_all')
事实上,这个 key_prefix 既不是 key 的前缀,也不是整个 key,它应该叫 key 的后缀更合理,真正保存的 key(存在那里取决于配置,可以有内存缓存SimpleCache、redis缓存等等)前缀是这个样子的:**flask_cache_**
,而无论是 path 还是 key_prefix,都会在 hash 之后拼接在后面。
普通 function 缓存控制
简单函数
如果是普通的 function,要使用 @cache.memoize 装饰器,同样支持 timeout 参数,如下:
@cache.memoize(timeout=60)
def get_number():
return 5
删除 memoize 要更直观一些,直接传函数就可以啦:
del_res = cache.delete_memoize(get_number)
如果该函数有参数:
@cache.memoize(timeout=60)
def get_number(x):
return 5 + x
删除时加参数,表示只删除这个参数对应的缓存,不加参数,表示删除该函数的所有实参值对应缓存:
del_res = cache.delete_memoize(get_number, 5) # 只删除x=5的缓存
del_res = cache.delete_memoize(get_number) # 删除所有 get_number 缓存
类函数
这时第二个坑来了,如果这是个类函数呢?
@cache.memoize(timeout=60)
class Calc:
@classmethod
def get_number(x):
return 5 + x
删除时,只传函数名,或者函数名加参数,是删不掉的:
del_res = cache.delete_memoize(Calc.get_number, 5) # 无法删除x=5的缓存
del_res = cache.delete_memoize(Calc.get_number) # 无法删除所有 get_number 缓存
官方文档说,“要把类当做第一个参数传进来”,这个的表述非常容易误解,实际上应该是参数列表里的第一个,所以要像下面这样传:
del_res = cache.delete_memoize(Calc.get_number, Calc, 5) # 删除x=5的缓存
del_res = cache.delete_memoize(Calc.get_number, Calc) # 删除所有 get_number 缓存