lee-pai-long
5/17/2017 - 1:31 AM

Flask template decorator.

Flask template decorator.

"""Flask template decorator example.

:examples:

.. code-block:: python

    # without the decorator
    @app.route('/')
    def index():
        return render_template('index.html',
                                welcome_message='Welcome to my App')

    # specifying the template
    @app.route('/')
    @template('index.html')
    def index():
        return dict(welcome_message='Welcome to my App')

    # associating endpoint to template name
    @app.route('/')
    @template()
    def index():
        return dict(welcome_message='Welcome to my App')

:sources: - https://goo.gl/MGP1aU
"""

from functools import wraps
from flask import request, render_template

def template(tpl=None):
    """Flask template 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.

    :arguments:
        - <tpl>(str): Name of the template to render.
                      If no name is provided, it will use the endpoint
                      of the URL map, with dots converted to
                      slashes + '.html'.

    :returns:
        - <decorator>(function): The inner decorator function.
    """

    def decorator(f):
        """Inner decorator.

        :arguments:
            - <f>(function): The function to decorate.

        :returns:
            - <wrapper>(function): the wrapper function.
        """

        @wraps(f)
        def wrapper(*args, **kwargs):
            """The wrapper function.

            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 we can still use the redirect function or return
            simple strings.
            """

            template = tpl
            if template is None:
                template = request.endpoint.replace('.', '/') + '.html'

            ctx = f(*args, **kwargs)
            if ctx is None:
                ctx = {}
            elif not isinstance(ctx, dict):
                return ctx

            return render_template(template, **ctx)

        return wrapper

    return decorator