One of the great challenges we face once the application is created is optimizing it, so that it consumes fewer resources and also returns responses more quickly; these aspects are required under many circumstances, for example, for SEO.
Once you have generated test data in Flask, we are now going to see how we can generate a cache for that data.
Page loading speed is one of the most important factors that will determine the success or failure of a web application.
Flask Caching solves this by allowing data to be stored in a cache, so that it can be returned more quickly; this data is usually database records or processed HTML documents. In this way, when a request is received from the user, it checks if it is in the cache:
- If the results are in the cache, the cached results are returned.
- If the results are not in the cache, they are generated as implemented in the controller/view and then saved in the cache.
Installation and Initial Configuration
We are going to install Flask Caching with:
$ pip install Flask-CachingThe next step is to register it at the application level:
app\my_app\__init__.py
from flask_caching import Cache
***
#cache
cache = Cache()
cache.init_app(app)
# blueprints
***The next step is to configure the cache storage, which can be any of the ones you can check in the following link:
https://flask-caching.readthedocs.io/en/latest/#built-in-cache-backends
We will use:
my_app\config.py
class DevConfig(Config):
***
CACHE_TYPE = 'SimpleCache'Regarding the cache type (CACHE_TYPE), there are several options depending on the environment:
- Simple: It is the default option and uses the system memory.
- Redis: Ideal for high-traffic production environments (requires having Redis installed).
The SimpleCache option tells Flask Cache to store the results in memory within a Python dictionary, which, for the vast majority of Flask applications, will be sufficient.
Cache Implementation in Routes: Storing templates and functions
To cache the result of a controller/view, it is enough to indicate the cache.cached decorator:
my_app\tasks\controllers.py
from my_app import cache
***
@taskRoute.route('/')
@cache.cached(timeout=60)
def index():
return render_template('dashboard/task/index.html', tasks=operations.pagination(request.args.get('page', 1, type=int), request.args.get('size', 10, type=int)))The timeout parameter specifies how many seconds the result cache should last.
When using the cache in a view, the route decorator must be placed before the cache decorator.
Simulating Heavy Loads
Since we work on localhost, responses are usually instantaneous. To appreciate the benefit of the cache, we are going to simulate a heavy task (like a slow database connection or image processing) using Python's sleep function:
import time
from flask import Blueprint
@products.route('/test2')
@cache.cached(timeout=60) # Apply the cache decorator
def test2():
time.sleep(3) # Pause the application for 3 seconds
return "Hello World"Caching functions without parameters
Controller results are not the only things that can be cached. To cache any Python function, simply add a similar decorator to the function definition, as follows:
@cache.cached(timeout=60, key_prefix='unique_key')
def myFunction():
***The key_prefix argument is necessary so that Flask Caching can store the results of non-view functions. The value must be unique for each function we want to cache.
Caching functions with parameters
The previous decorator cannot be used in functions that have arguments; in these cases, we must use the memoize decorator so they are included in the cache:
class Person(db.Model):
@cache.memoize(50)
def has_membership(self, role_id):
return Group.query.filter_by(user=self, role_id=role_id).count() >= 1Memoize is also designed for methods, as it will take into account the identity of the 'self' or 'cls' argument as part of the cache key.
While developing the application, we don't want the cache functions to be running since screens change as we update it; to avoid this, we set the CACHE_TYPE variable to null for the development configuration:
my_app\config.py
class Config(object):
***
CACHE_TYPE = 'SimpleCache'
class DevConfig(Config):
***
CACHE_TYPE = 'null'When to use Cache?
It is important to have criteria when applying these tools. In administrative modules (where products are listed for editing), the cache is usually not very useful, as the administrator needs to see changes in real-time.
However, in the final customer view (such as a blog or a public catalog), the cache is fundamental:
- User volume: If 1,000 users consult the same post, it makes no sense to process the same query a thousand times.
- SEO: Search engines like Google value a minimum response time positively.
Function Caching and Memorization
If you need to save the result of a function that is not a route (for example, a complex calculation in a model), you can use the same decorator.
- @cache.cached: For functions without arguments.
- @cache.memoize: It is the ideal function when the response depends on certain arguments (such as a user ID). Thus, the system will save a different cache for each combination of parameters.
@cache.memoize(timeout=50)
def heavy_query(parameter):
# Database logic...
return resultNext step, implement a roles and permissions system in Flask.