作为一个微框架Flask没有内置的缓存功能,但是,有werkzeug cache API和一个很好的扩展,以提供其缓存功能到您的Flask应用程序,该扩展由@thadeusb创建,是非常容易实现和使用。
安装
在你的env通过PyPI安装它(推荐)
pip install Flask-Cache
如果您需要最近的更改或错误修复,您还可以直接从源代码安装它
pip install https://github.com/thadeusb/flask-cache/tarball/master
配置
您可以在应用设置中设置一组配置键,但最重要的是由CACHE_TYPE键定义的缓存后端。
缓存类型解析为一个导入字符串,它需要是一个对象实现werkzeug cache api,但是werkzeug.contrib.cache实现有一些别名
默认情况下,CACHE_TYPE是Null,这意味着您的应用程序将没有缓存,因此您需要选择以下选项:
null | No Cache - NullCache simple | Will use in memory pickle and is recommended only for single process development server memcached | Requires pylibmc or memcached and requires memcached configuration in settings redis | Requires redis, werkzeug 0.7 and redis configuration in settings filesystem | The same as simple but stores the pickle in a cache_dir gaememcached | For Google AppEngine saslmemcached | The same as memcached but for SASL - pylibmc required
完整的选项和配置变量在pythonhosted.org/Flask-Cache/#configuring-flask-cache
一个简单的Flask应用程序
一个名为 app.py的文件
import time from flask import Flask app = Flask(__name__) @app.route("/") def view(): return time.ctime() if __name__ == "__main__": app.run(port=5000, debug=True, host='0.0.0.0')
运行python app.py,并在浏览器中打开https://localhost:5000,然后按F5(刷新)查看当前日期和时间。
在视图中启用Flask-Cache
现在我们要在这个小应用程序上启用缓存,以避免刷新当前时间(对于这个例子,我们使用当前时间作为返回,但想象它可能是一个大数据集或巨大的计算)
一个名为 cached_app.py的文件
import time from flask import Flask # import the flask extension from flask.ext.cache import Cache app = Flask(__name__) # define the cache config keys, remember that it can be done in a settings file app.config['CACHE_TYPE'] = 'simple' # register the cache instance and binds it on to your app app.cache = Cache(app) @app.route("/") @app.cache.cached(timeout=300) # cache this view for 5 minutes def cached_view(): return time.ctime() if __name__ == "__main__": app.run(port=5000, debug=True, host='0.0.0.0')
运行上面的python cached_app.py,并在浏览器中打开https://localhost:5000,然后按F5(刷新),看到当前日期和时间,现在缓存5分钟。
@ cache.cached decorator接受该视图的request.path并使用它作为缓存键,如果由于任何原因你需要一个不同的键,你可以传递一个key_prefix参数到装饰器。在这种情况下,如果您传递一个包含%s占位符的key_prefix,它将被当前的request.path所替换
以上是Flask应用程序和使用缓存的最简单和常规的例子,但如果你的应用程序是使用工厂模式,蓝图,基于类的视图或视图位于不同的模块,你将需要使用高级方法。
缓存常规函数
相同的缓存装饰器可以用于缓存常规函数,但在这种情况下,您需要指定key_prefix参数,否则它将使用request.path,如果您有许多缓存函数,它可能会导致冲突。
对于这个例子,我们将使用this模块并从Python之禅中随机提取引用一段。
名为cached_function_app.py的文件
import time import random from this import s, d from string import translate, maketrans from flask.ext.cache import Cache from flask import Flask app = Flask(__name__) app.config['CACHE_TYPE'] = 'simple' app.cache = Cache(app) @app.cache.cached(timeout=10, key_prefix="current_time") def get_current_time(): return time.ctime() def random_zen_quote(): """Pick a random quote from the Zen of Python""" transtable = maketrans("".join(d.keys()), "".join(d.values())) return random.choice(translate(s, transtable).split("\n")[2:]) @app.route("/") def zen(): return """ <ul> <li><strong>It is cached:</strong> {cached}</li> <li><strong>It is not cached:</strong> {not_cached}</li> </ul> """.format( cached=get_current_time(), not_cached=random_zen_quote() ) if __name__ == "__main__": app.run(debug=True, port=5000, host='0.0.0.0')
现在运行python cached_function_app.py,并打开https://localhost:5000,当点击F5刷新,你会看到当前时间缓存5分钟和随机更新引用,你可以改变缓存来看效果。
def get_current_time(): return time.ctime() @app.cache.cached(timeout=10, key_prefix="zen_quote") def random_zen_quote(): transtable = maketrans("".join(d.keys()), "".join(d.values())) return random.choice(translate(s, transtable).split("\n")[2:]) @app.route("/") def zen(): return """ <ul> <li><strong>It is not cached:</strong> {cached}</li> <li><strong>It is cached:</strong> {not_cached}</li> </ul> """.format( cached=get_current_time(), not_cached=random_zen_quote() )
注意:因为我们正在导入该this示例的模块,所以您将在Flask终端中看到禅的引用,对于这没有影响。
缓存modular views
现在这个例子,当你有你的应用程序分裂成两个或更多的文件,以更好的组织
在一个名为app文件夹中放3个文件__init__.py,app.py和views.py
app/__init__.py 是一个空文件
app/views.py import time import random from this import s, d from string import translate, maketrans def get_current_time(): return time.ctime() def random_zen_quote(): transtable = maketrans("".join(d.keys()), "".join(d.values())) return random.choice(translate(s, transtable).split("\n")[2:]) def zen_view(): return """ <h1>Cached for 10 seconds!</h1> <ul> <li>{time}</li> <li>{quote}</li> </ul> """.format( time=get_current_time(), quote=random_zen_quote() )
现在你可以看到上面已经定义的视图函数文件,作为一个分离出来的文件,为避免循环导入,我们不建议使用@ app.route或者@ app.cache,所以这个视图将是应用程序无关,我们要注册其url规则和缓存在主应用程序文件中。
当你的应用有太多的视图,想要一个更好的组织,这种结构是需要的。
注意:为了更好的组织,主要推荐的模式是蓝图,我将进一步解释。
app/app.py
现在在主应用程序中,我们需要导入我们的视图,明确缓存装饰器,并注册其url。
from flask import Flask from flask.ext.cache import Cache from views import zen_view app = Flask(__name__) app.config['CACHE_TYPE'] = 'simple' app.cache = Cache(app) # explicitly apply the cache in the old-style decoration way cached_zen_view = app.cache.cached(timeout=10)(zen_view) # explicitly register the cached view url mapping app.add_url_rule("/", view_func=cached_zen_view) if __name__ == "__main__": app.run(debug=True, port=5000, host='0.0.0.0')
注意:您还可以在不同的文件中分离缓存实例,以便延迟加载,我们将在下一个示例中看到
缓存 Blueprint views
如前所述,在Flask应用程序中最好的模式是Blueprint模式,这是一种创建分离的“元应用程序”的方式,将在初始化时连接到主应用程序,这里的问题是蓝图是指以便可以由许多不同的应用程序重用,因此缓存控制调用应该被动态化。
为了避免循环导入,您需要创建与应用程序实例分离的缓存实例(如果您要构建更复杂的应用程序,可以考虑切换到应用程序工厂模式)。
按照以下结构创建一个blueprint_app
cached_blueprint_app/ ├── app.py ├── cache.py ├── blueprints │ ├── __init__.py │ └── zen_blueprint.py └── __init__.py
cache.py
from flask.ext.cache import Cache cache = Cache()
我们可以创建一个虚拟的延迟缓存实例,它将在以后当视图被调用时初始化。对于在应用程序中,我们将重新导入相同的缓存实例和调用init_app方法。
基础的 blueprints/zen_blueprint.py
import time import random from this import s, d from string import translate, maketrans from flask import Blueprint from cache import cache zen = Blueprint('zen', __name__) def get_current_time(): return time.ctime() def random_zen_quote(): transtable = maketrans("".join(d.keys()), "".join(d.values())) return random.choice(translate(s, transtable).split("\n")[2:]) @zen.route("/") @cache.cached(timeout=20) def zen_view(): return """ <h1>Cached for 20 seconds!</h1> <ul> <li>{time}</li> <li>{quote}</li> </ul> """.format( time=get_current_time(), quote=random_zen_quote() )
注意:在一个真正的应用程序中,你将需要模块化分离出来的视图,辅助等,并将你的蓝图打包到一个Python包。
主程序 app.py
from flask import Flask from blueprints.zen_blueprint import zen from cache import cache app = Flask(__name__) app.config['CACHE_TYPE'] = 'simple' cache.init_app(app) app.register_blueprint(zen) if __name__ == "__main__": app.run(debug=True, port=5000, host='0.0.0.0')
注意,我们创建了一个缓存的虚拟实例cache.py然后使用该实例来装饰蓝图视图,然后使用init_app方法在app.py中初始化缓存。这是可能的,因为Flask初始化循环和Flask-Cache扩展中的优秀实现,处理这种情况,如果你打算写自己的Flask扩展看看Flask-Cache源代码。
通过调用运行应用程序python cached_blueprint_app/app.py并打开https://localhost:5000以查看缓存20秒的蓝图视图。
缓存MethodView
让我们使用相同的cached_blueprint_app例子,但将zen_viewin转换为一个MethodView
更改zen_blueprint.py为:
import time import random from this import s, d from string import translate, maketrans from flask import Blueprint from flask.views import MethodView from cache import cache zen = Blueprint('zen', __name__) class ZenView(MethodView): @cache.cached(30) def get(self): return """ <h1>Cached for 30 seconds!</h1> <ul> <li>{time}</li> <li>{quote}</li> </ul> """.format( time=self.get_current_time(), quote=self.random_zen_quote() ) @staticmethod def get_current_time(): return time.ctime() @staticmethod def random_zen_quote(): transtable = maketrans("".join(d.keys()), "".join(d.values())) return random.choice(translate(s, transtable).split("\n")[2:]) zen.add_url_rule("/", view_func=ZenView.as_view('zen'))
方法视图将HTTP方法名称作为GET,POST,DELETE映射到视图方式作为get,post,delete等,所以我们需要做的是创建一个方法get并使用装饰器装饰它@cache.cached。
注意:由于从调用者的角度来看隐式自我,你不能对视图的各个方法使用常规视图装饰器,但Flask-Cache是一个例外,因为它的实现允许在单个方法中使用缓存装饰器。记住这一点。
另外,你可能想要缓存所有的方法在一个视图,为了你可以缓存dispatch_request方法,或更好地,你可以装饰整个视图。
缓存调度程序
class ZenView(MethodView): @cache.cached(timeout=30) def dispatch_request(self): return super(ZenView, self).dispatch_request() ...
缓存整个视图(推荐)
zen = Blueprint('zen', __name__) class ZenView(MethodView): ... cached_zen_view = cache.cached(timeout=50)(ZenView.as_view('zen')) zen.add_url_rule("/", view_func=cached_zen_view)
缓存template blocks
Flask缓存有一个能够缓存模板块的模板标签,让我们改变ZenView使用Jinja2模板
在 zen_blueprint.py
import time import random from this import s, d from string import translate, maketrans from flask import Blueprint, render_template from flask.views import MethodView zen = Blueprint('zen', __name__) class ZenView(MethodView): def get(self): return render_template( 'zen.html', get_random_quote=self.random_zen_quote ) @staticmethod def get_current_time(): return time.ctime() @staticmethod def random_zen_quote(): transtable = maketrans("".join(d.keys()), "".join(d.values())) return random.choice(translate(s, transtable).split("\n")[2:]) zen.add_url_rule("/", view_func=ZenView.as_view('zen'))
现在我们需要在中创建一个模板文件 cached_blueprint_app/templates/zen.html
<h3> Random Zen of Python </h3> <strong>{{get_random_quote()}}</strong>
运行应用程序python cached_blueprint_app/app.py并打开http:// localhost:5000,你会看到一个随机报价刷新每次你推F5,让它缓存30秒。
更改zen.html模板
{% cache 30 %} <h3> Random Zen of Python </h3> <strong>{{get_random_quote()}}</strong> {% endcache %} 现在保存文件并刷新以查看缓存30秒的内容。 使用memoize装饰器缓存函数和带有变量参数的视图 有时,yout视图和函数接收可能来自url映射或直接到函数调用的参数,您可能想缓存视图或功能,并使用参数作为缓存其不同结果的键,Flask-Cache有一个不同的装饰器那。 注意:对于没有接收参数的函数,cached()和memoize()实际上是相同的。 现在用一个简单的应用程序 memoize_app.py
现在运行python memoize_app.py并打开https://localhost:5000/yourname,并注意该函数将被缓存为您在url中作为参数传递的每个不同的名称。
缓存任意对象
有时候装饰器不能被使用,你需要在缓存上显式地设置或获取一些东西。
在视图或蓝图内,您可以使用current_app
from flask import current_app def some_function(): cached = current_app.cache.get('a_key') if cached: return cached result = do_some_stuff() current_app.cache.set('a_key', result, timeout=300) return result
或者如果使用separete缓存实例,你可以直接这样做
from cache import cache def function(): cached = cache.get('a_key') if cached: return cached result = do_some_stuff() cache.set('a_key', result, timeout=300) return result
清除缓存
您可以创建一个脚本来清除缓存,或者在需要时使用它的函数
from flask.ext.cache import Cache from yourapp import app cache = Cache() def main(): cache.init_app(app) with app.app_context(): cache.clear() if __name__ == '__main__': main()
警告:某些后端实施不支持完全清除大小写。此外,如果你不使用密钥前缀,一些实现(例如Redis)将刷新整个数据库。确保您不在缓存数据库中存储任何其他数据。
有很多例子和很好记录的API在flask-Cache网站https://pythonhosted.org/Flask-Cache/,你也可以按照Flask-Cache 文档中的示例创建自己的缓存后端。
这是一篇翻译的文章,工具是谷歌翻译,看不懂也没办法!
文章出处:https://brunorocha.org/python/flask/using-flask-cache.html
学习了
慢慢学习中,对我来讲比较深