View Decorators

    So let’s implement such a decorator. A decorator is a function that wraps and replaces another function. Since the original function is replaced, you need to remember to copy the original function’s information to the new function. Use functools.wraps() to handle this for you.

    This example assumes that the login page is called and that the current user is stored in g.user and is None if there is no-one logged in.

    To use the decorator, apply it as innermost decorator to a view function. When applying further decorators, always remember that the decorator is the outermost.

    1. @app.route('/secret_page')
    2. @login_required
    3. def secret_page():
    4. pass

    Note

    The next value will exist in request.args after a GET request for the login page. You’ll have to pass it along when sending the POST request from the login form. You can do this with a hidden input tag, then retrieve it from request.form when logging the user in.

    Here is an example cache function. It generates the cache key from a specific prefix (actually a format string) and the current path of the request. Notice that we are using a function that first creates the decorator that then decorates the function. Sounds awful? Unfortunately it is a little bit more complex, but the code should still be straightforward to read.

    The decorated function will then work as follows

    1. get the unique cache key for the current request based on the current path.

    2. get the value for that key from the cache. If the cache returned something we will return that value.

    3. otherwise the original function is called and the return value is stored in the cache for the timeout provided (by default 5 minutes).

    1. from functools import wraps
    2. from flask import request
    3. @wraps(f)
    4. def decorated_function(*args, **kwargs):
    5. cache_key = key.format(request.path)
    6. rv = cache.get(cache_key)
    7. if rv is not None:
    8. return rv
    9. rv = f(*args, **kwargs)
    10. cache.set(cache_key, rv, timeout=timeout)
    11. return rv
    12. return decorated_function
    13. return decorator

    Notice that this assumes an instantiated cache object is available, see Caching.

    A common pattern invented by the TurboGears guys a while back is a templating decorator. The idea of that decorator is that you return a dictionary with the values passed to the template from the view function and the template is automatically rendered. With that, the following three examples do exactly the same:

    As you can see, if no template name is provided it will use the endpoint of the URL map with dots converted to slashes + '.html'. Otherwise the provided template name is used. When the decorated function returns, the dictionary returned is passed to the template rendering function. If None is returned, an empty dictionary is assumed, if something else than a dictionary is returned we return it from the function unchanged. That way you can still use the redirect function or return simple strings.

    Here is the code for that decorator:

    1. from functools import wraps
    2. def templated(template=None):
    3. def decorator(f):
    4. @wraps(f)
    5. def decorated_function(*args, **kwargs):
    6. template_name = template
    7. if template_name is None:
    8. template_name = f"{request.endpoint.replace('.', '/')}.html"
    9. ctx = f(*args, **kwargs)
    10. if ctx is None:
    11. ctx = {}
    12. elif not isinstance(ctx, dict):
    13. return ctx
    14. return render_template(template_name, **ctx)
    15. return decorated_function

    When you want to use the werkzeug routing system for more flexibility you need to map the endpoint as defined in the to a view function. This is possible with this decorator. For example: