本文共 19785 字,大约阅读时间需要 65 分钟。
As a micro framework Flask does not have built-in cache functionality, however, there is werkzeug cache API and an excellent extension to provide its caching functionality to your Flask apps, that extension was created by @thadeusb and is very easy to implement and use.
但是,由于Flask不具有内置的缓存功能,因此它具有werkzeug缓存API和出色的扩展,可以为您的Flask应用程序提供其缓存功能,该扩展由@thadeusb创建,非常易于实现和使用。
In your env install it via PyPI (recommended)
在您的环境中通过PyPI安装(推荐)
pip install Flask-Cache pip install Flask-Cache
You can also install it directly from source code if you need recent changes or bugfixes
如果您需要最近的更改或错误修正,也可以直接从源代码安装它
There is a set of configuration keys you can put in your app settings, but the most important is the cache backend defined by the CACHE_TYPE key.
您可以在应用程序设置中放入一组配置键,但最重要的是由CACHE_TYPE键定义的缓存后端。
The cache type resolves to an import string which needs to be an object implementing the werkzeug cache api, but there is some aliases to the werkzeug.contrib.cache implementations
缓存类型解析为导入字符串,该导入字符串必须是实现werkzeug缓存api的对象,但是werkzeug.contrib.cache实现有一些别名
By default the CACHE_TYPE is Null which means that your app will have no cache, so you need to choose of the options below:
默认情况下,CACHE_TYPE为Null,这意味着您的应用程序将没有缓存,因此您需要选择以下选项:
Full options and config variables are in
完整的选项和配置变量位于
a file named app.py
一个名为app.py
的文件
import timefrom flask import Flaskapp = Flask(__name__)@app.route("/")def view(): return time.ctime()if __name__ == "__main__": app.run(port=5000, debug=True, host='0.0.0.0')import timefrom flask import Flaskapp = Flask(__name__)@app.route("/")def view(): return time.ctime()if __name__ == "__main__": app.run(port=5000, debug=True, host='0.0.0.0')
Run the above with python app.py
and open in your browser and hit F5 (refresh) to see the current date and time.
使用python app.py
运行以上python app.py
然后在浏览器中打开 ,然后按F5(刷新)以查看当前日期和时间。
Now we want to enable caching on that small application to avoid the refresh of the current time (for this example we are using current time as return but imagine that it could be a large dataset or huge calculations)
现在,我们要在该小型应用程序上启用缓存以避免刷新当前时间(在本示例中,我们将当前时间用作返回值,但可以想象它可能是大型数据集或大量计算)
a file named cached_app.py
一个名为cached_app.py
的文件
Run the above with python cached_app.py
and open in your browser and hit F5 (refresh) to see that the current date and time is now cached for 5 minutes.
使用python cached_app.py
运行以上python cached_app.py
然后在浏览器中打开 ,然后按F5(刷新)以查看当前日期和时间已被缓存5分钟。
@cache.cached decorator takes the request.path for that view and use this as cache key, if for any reason you need a different key you can pass a key_prefix argument to the decorator. In this case if you pass a key_prefix containing the %s placeholder it will be replaced by the current request.path
@ cache.cached装饰器采用该视图的request.path并将其用作缓存键,如果出于任何原因需要其他键,则可以将key_prefix参数传递给装饰器。 在这种情况下,如果您传递包含%s占位符的key_prefix,它将被当前的request.path替换。
The above is the simplest and regular example of Flask app and the use of cache, but, if your app is designed using application factories, blueprints, class based views or views located in different modules you will need to use advanced approach.
上面是Flask应用程序和缓存使用的最简单且常规的示例,但是,如果您的应用程序是使用应用程序工厂,蓝图,基于类的视图或位于不同模块中的视图设计的,则需要使用高级方法。
The same cached decorator can be used to cache regular functions, but in this case you will need to specify the key_prefix argument, otherwise it will use the request.path which can lead to conflicts if you have many cached functions.
可以使用相同的缓存装饰器来缓存常规函数,但是在这种情况下,您需要指定key_prefix参数,否则它将使用request.path,如果您有很多缓存的函数,则可能导致冲突。
For this example we are going to use the this
module and extract a random quote from the Zen of Python.
对于此示例,我们将使用this
模块并从Python的Zen中提取随机引号。
A file named cached_function_app.py
名为cached_function_app.py
的文件
import timeimport randomfrom this import s, dfrom string import translate, maketransfrom flask.ext.cache import Cachefrom flask import Flaskapp = 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 """
Now running python cached_function_app.py
and opening when hitting F5 to refresh you will see the current time cached for 5 minutes and the random quote updated, you can switch the cache just to see the efect.
现在运行python cached_function_app.py
并在按F5刷新时打开 ,您将看到当前时间已缓存5分钟,并且随机报价已更新,您可以切换缓存以查看效果。
NOTE: Because we are importing the
this
module for the example, you will see the Zen quotes in your flask terminal, but there is no problem with this.注意:因为我们正在导入示例的
this
模块,所以您将在flask终端中看到Zen引号,但是这样做没有问题。
Now an example when you have your app splitted in two or more files for better organization
现在是一个示例,其中将您的应用拆分为两个或更多文件以更好地组织
in a folder called app
put 3 files__init__.py
, app.py
and views.py
在名为app
的文件夹中,放入3个文件__init__.py
. app.py
, app.py
和views.py
app/__init__.py
is an empty file
app/__init__.py
是一个空文件
app/views.py
app/views.py
import timeimport randomfrom this import s, dfrom string import translate, maketransdef 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 """Cached for 10 seconds!
as you can see the above file defined view functions, as it it a separated file, to avoid circular imports we are not recommended to use @app.route neither @app.cache so this views will be app agnostic and we are going to register its url rules and caching in the main app file.
你可以看到定义视图功能上面的文件,因为它是一个分离的文件,避免循环进口,我们不建议使用@ app.route既不@ app.cache所以这个观点将是应用无关的 ,我们要登记其网址规则和缓存在主应用程序文件中。
That kind of structure is needed when your app has too many views and want a better organization.
当您的应用程序具有太多视图并希望有一个更好的组织时,就需要这种结构。
NOTE: For better organization the mostly recommended pattern is Blueprints which I will explain further.
注意:为了更好的组织,最推荐的模式是“蓝图”,我将进一步解释。
app/app.py
app/app.py
Now in the main app we need to import our views, explicitly decorate for caching and also register its urls.
现在,在主应用程序中,我们需要导入视图,显式装饰以进行缓存,并注册其url。
NOTE: You can also separate the cache instance in a different file for lazy initialization as we are going to see in the next example
注意:您也可以将缓存实例分离到另一个文件中以进行延迟初始化,如我们在下一个示例中将看到的那样
As mentioned before, the best pattern to follow in Flask applications is the Blueprint pattern which is a way to create separated ‘meta-apps’ that will be connected to your main application in the time of initialization, the problem here is that Blueprints are meant to be reusable by many different applications, so the delegation of cache control should be dynamized.
如前所述,在Flask应用程序中遵循的最佳模式是Blueprint模式,这是一种创建单独的“元应用程序”的方法,该应用程序将在初始化时连接到您的主应用程序,这里的问题是Blueprints意味着可以被许多不同的应用程序重用,因此应该动态化缓存控制的委托。
In order to avoid circular imports you will want to create your cache instance separate from your application instance (you may want to consider switching to the app factory module if you are building something more complex).
为了避免循环导入,您需要将缓存实例与应用程序实例分开创建(如果要构建更复杂的东西,则可能要考虑切换到应用程序工厂模块)。
Create a folder called blueprint_app
with the following structure
使用以下结构创建一个名为blueprint_app
的文件夹
cached_blueprint_app/├── app.py├── cache.py├── blueprints│ ├── __init__.py│ └── zen_blueprint.py└── __init__.pycached_blueprint_app/├── app.py├── cache.py├── blueprints│ ├── __init__.py│ └── zen_blueprint.py└── __init__.py
The cache.py
cache.py
we can create a dummy lazy cache instance, that will be initialized in the future when the view will be called. For that in the app we are going to reimport the same cache instance and call init_app
method.
我们可以创建一个虚拟的惰性缓存实例,该实例将在以后调用视图时进行初始化。 为此,在应用程序中,我们将重新导入相同的缓存实例并调用init_app
方法。
The basic blueprints/zen_blueprint.py
基本blueprints/zen_blueprint.py
import timeimport randomfrom this import s, dfrom string import translate, maketransfrom flask import Blueprintfrom cache import cachezen = 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 """Cached for 20 seconds!
NOTE: In a real application you will want to modularize it separating the views, helpers etc and promoting your blueprint to a Python package.
注意:在实际的应用程序中,您将需要对其进行模块化,以分隔视图,助手等并将您的蓝图升级为Python包。
The main app.py
主app.py
Notice that we created a dummy instance of cache in cache.py
and then used that instance to decorate the blueprints views, then the cache was initialized in app.py
with init_app
method. That is possible because of the Flask initialization cycle and the excellent implementation in Flask-Cache extension that takes care of this case, if you plan to write yor own Flask extension take a look at the Flask-Cache source code.
请注意,我们在cache.py
创建了一个缓存的虚拟实例,然后使用该实例来装饰蓝图视图,然后使用init_app
方法在app.py
中初始化了缓存。 由于Flask的初始化周期以及在这种情况下Flask-Cache扩展中出色的实现,使得这种情况成为可能,如果您打算编写自己的Flask扩展,请查看Flask-Cache源代码。
Run the application by calling python cached_blueprint_app/app.py
and open to see the blueprint view cached for 20 seconds.
通过调用python cached_blueprint_app/app.py
运行应用程序,然后打开以查看缓存了20秒的蓝图视图。
Lets use the same cached_blueprint_app
example but turning the zen_view
in to a MethodView
让我们使用相同的cached_blueprint_app
示例,但将zen_view
转到MethodView
Change your zen_blueprint.py
to:
将您的zen_blueprint.py
更改为:
import timeimport randomfrom this import s, dfrom string import translate, maketransfrom flask import Blueprintfrom flask.views import MethodViewfrom cache import cachezen = Blueprint('zen', __name__)class ZenView(MethodView): @cache.cached(30) def get(self): return """Cached for 30 seconds!
Method views maps HTTP method names as GET, POST, DELETE to the view methos as get, post, delete etc, So all we needed to do is to create a method called get
and decorate it with @cache.cached
decorator.
方法视图将HTTP方法名称(如GET,POST,DELETE)映射为视图方法(如get,post,delete等),因此我们所需要做的就是创建一个名为get
的方法,并使用@cache.cached
装饰器@cache.cached
修饰。
NOTE: Due to the implicit self from the caller’s perspective you cannot use regular view decorators on the individual methods of the view however, Flask-Cache is one exception because its implementation allow the use of cached decorator in individual methods. Keep this in mind.
注意:由于从调用者的角度而言隐式的自我,您不能在视图的各个方法上使用常规视图装饰器,但是Flask-Cache是一个例外,因为其实现允许在各个方法中使用缓存的装饰器。 请记住这一点。
Alternativelly you may want to cache all the methods in a view, for that you can cache the dispatch_request method or even better you can decorate the whole view.
或者,您可能希望在视图中缓存所有方法,因为您可以缓存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)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)
Flask cache comes with a template tag able to cache template blocks, lets change our ZenView
to use a Jinja2 template
Flask缓存带有一个模板标签,该标签能够缓存ZenView
板块,让我们更改ZenView
以使用Jinja2模板
in zen_blueprint.py
在zen_blueprint.py
Now we need to create a template file in cached_blueprint_app/templates/zen.html
现在我们需要在cached_blueprint_app/templates/zen.html
创建一个模板文件
Random Zen of Python
{ {get_random_quote()}}Random Zen of Python
{ {get_random_quote()}}
Running the application with python cached_blueprint_app/app.py
and opening you will see a random quote refreshed every time you push F5, lets cache it for 30 second.
使用python cached_blueprint_app/app.py
运行应用程序并打开您每次按下F5都会看到刷新的随机报价,将其缓存30秒。
Change the zen.html
template
更改zen.html
模板
Now save the file and refresh to see the content cached for 30 seconds.
现在保存文件并刷新以查看缓存了30秒的内容。
Sometimes yout views and functions receives arguments which can come from url mapping or directly to the function call, yiou may want to cache the view or funtion and use the arguments as keys to cache its different results, Flask-Cache has a different decorator for doing that.
有时,您的视图和函数接收到的参数可能来自网址映射或直接指向函数调用,您可能想缓存视图或函数,并使用这些参数作为键来缓存其不同的结果,Flask-Cache具有执行此操作的不同装饰器那。
NOTE: With functions that do not receive arguments, cached() and memoize() are effectively the same.
注意:对于不接收参数的函数,cached()和memoize()实际上是相同的。
Now with a simple application memoize_app.py
现在有了一个简单的应用程序memoize_app.py
import timefrom flask.ext.cache import Cachefrom flask import Flaskapp = Flask(__name__)app.config['CACHE_TYPE'] = 'simple'app.cache = Cache(app)@app.cache.memoize(timeout=5)def get_current_time_and_name(name): return "%s - %s" % (name, time.ctime())@app.route("/")def view(name): return get_current_time_and_name(name)if __name__ == "__main__": app.run(debug=True, port=5000, host='0.0.0.0')import timefrom flask.ext.cache import Cachefrom flask import Flaskapp = Flask(__name__)app.config['CACHE_TYPE'] = 'simple'app.cache = Cache(app)@app.cache.memoize(timeout=5)def get_current_time_and_name(name): return "%s - %s" % (name, time.ctime())@app.route("/ ")def view(name): return get_current_time_and_name(name)if __name__ == "__main__": app.run(debug=True, port=5000, host='0.0.0.0')
Now run python memoize_app.py
and open and note that the function will be cached for each different name you pass as argument in the url.
现在运行python memoize_app.py
并打开 ,请注意,该函数将针对您作为url中的参数传递的每个不同名称进行缓存。
There are some times when decorators cannot be used and you need to explicitly set or get some thing on the cache.
在某些情况下,不能使用装饰器,并且您需要显式设置或在缓存中获取某些东西。
Inside a view or a blueprint you can use current_app
在视图或蓝图内,您可以使用current_app
Or if using a separete cache instance you can do this directly
或者,如果使用单独的缓存实例,则可以直接执行此操作
from cache import cachedef function(): cached = cache.get('a_key') if cached: return cached result = do_some_stuff() cache.set('a_key', result, timeout=300) return resultfrom cache import cachedef function(): cached = cache.get('a_key') if cached: return cached result = do_some_stuff() cache.set('a_key', result, timeout=300) return result
You can create a script to clear the cache, or a function to use it when needed
您可以创建一个脚本来清除缓存,也可以创建一个函数以在需要时使用它
WARNING: Some backend implementation do not support completely clearing the case. Also, if you’re not using key prefix, some implementation (e.g. Redis) will flush the whole database. Make sure you’re not storing any other data in your caching database.
警告:某些后端实现不支持完全清除大小写。 另外,如果您不使用键前缀,则某些实现(例如Redis)将刷新整个数据库。 确保您没有在缓存数据库中存储任何其他数据。
翻译自:
转载地址:http://niqwd.baihongyu.com/