Spec-Zone.ru › Flask 2.0

Декораторы представлений

В Python есть очень интересная функция, называемая декораторами функций. Это позволяет реализовать интересные вещи для веб-приложений. Поскольку каждое представление в Flask является функцией, декораторы могут использоваться для добавления дополнительной функциональности к одной или нескольким функциям. Декоратор route() — тот, который вы, вероятно, уже использовали. Но есть случаи использования для реализации собственных декораторов. Например, представьте, что у вас есть представление, которое должно использоваться только авторизованными пользователями. Если пользователь заходит на сайт и не авторизован, он должен быть перенаправлен на страницу входа. Это хороший пример случая использования, где декоратор — отличное решение.

Декоратор, требующий авторизации

Давайте реализуем такой декоратор. Декоратор — это функция, которая оборачивает и заменяет другую функцию. Поскольку исходная функция заменяется, вам нужно запомнить, чтобы скопировать информацию из исходной функции в новую функцию. Используйте functools.wraps(), чтобы справиться с этим за вас.

В этом примере предполагается, что страница входа называется 'login', а текущий пользователь хранится в g.user и является None, если никто не авторизован.

from functools import wraps
from flask import g, request, redirect, url_for

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if g.user is None:
            return redirect(url_for('login', next=request.url))
        return f(*args, **kwargs)
    return decorated_function

Чтобы использовать декоратор, примените его как самый внутренний декоратор к функции представления. При применении дополнительных декораторов всегда помните, что декоратор route() является самым внешним.

@app.route('/secret_page')
@login_required
def secret_page():
    pass

Примечание

Значение next будет существовать в request.args после запроса на страницу входа. Вам нужно будет передать его при отправке запроса POST с формы входа. Вы можете сделать это с помощью скрытого тега ввода, а затем извлечь его из request.form при входе пользователя в систему.

<input type="hidden" value="{{ request.args.get('next', '') }}"/>

Декоратор кэширования

Представьте, что у вас есть функция представления, которая выполняет дорогостоящие вычисления, и вы хотите кэшировать полученные результаты на определенный период времени. Для этого подойдет декоратор. Мы предполагаем, что вы настроили кэш, как описано в Кэшировании.

Вот пример функции кэширования. Она генерирует ключ кэша из определенного префикса (фактически, строки формата) и текущего пути запроса. Обратите внимание, что мы используем функцию, которая сначала создает декоратор, а затем декорирует функцию. Звучит ужасно? К сожалению, это немного сложнее, но код все равно должен быть легко читаемым.

Декорированная функция будет работать следующим образом

  1. получить уникальный ключ кэша для текущего запроса на основе текущего пути.
  2. получить значение для этого ключа из кэша. Если кэш вернул что-то, мы вернем это значение.
  3. в противном случае вызывается исходная функция, и возвращаемое значение сохраняется в кэше на указанный срок (по умолчанию 5 минут).

Вот код:

from functools import wraps
from flask import request

def cached(timeout=5 * 60, key='view/{}'):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            cache_key = key.format(request.path)
            rv = cache.get(cache_key)
            if rv is not None:
                return rv
            rv = f(*args, **kwargs)
            cache.set(cache_key, rv, timeout=timeout)
            return rv
        return decorated_function
    return decorator

Обратите внимание, что это предполагает, что доступен экземпляр объекта cache, см. Кэширование.

Декоратор шаблонов

Распространенный паттерн, изобретенный разработчиками TurboGears некоторое время назад, — декоратор шаблонов. Идея этого декоратора в том, что вы возвращаете словарь со значениями, переданными в шаблон из функции представления, и шаблон автоматически отрисовывается. Таким образом, следующие три примера делают ровно то же самое:

@app.route('/')
def index():
    return render_template('index.html', value=42)

@app.route('/')
@templated('index.html')
def index():
    return dict(value=42)

@app.route('/')
@templated()
def index():
    return dict(value=42)

Как видите, если имя шаблона не указано, используется конечная точка карты URL с точками, преобразованными в косые черты + '.html'. В противном случае используется предоставленное имя шаблона. Когда декорированная функция возвращает значение, возвращаемый словарь передается в функцию отрисовки шаблона. Если возвращается None, предполагается пустой словарь; если возвращается что-то другое, кроме словаря, мы возвращаем это значение из функции без изменений. Таким образом, вы по-прежнему можете использовать функцию перенаправления или возвращать простые строки.

Вот код этого декоратора:

from functools import wraps
from flask import request, render_template

def templated(template=None):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            template_name = template
            if template_name is None:
                template_name = f"'{request.endpoint.replace('.', '/')}.html'"
            ctx = f(*args, **kwargs)
            if ctx is None:
                ctx = {}
            elif not isinstance(ctx, dict):
                return ctx
            return render_template(template_name, **ctx)
        return decorated_function
    return decorator

Декоратор конечной точки

Если вы хотите использовать систему маршрутизации Werkzeug для большей гибкости, вам нужно сопоставить конечную точку, как определено в Rule, с функцией представления. Это возможно с помощью этого декоратора. Например:

from flask import Flask
from werkzeug.routing import Rule

app = Flask(__name__)
app.url_map.add(Rule('/', endpoint='index'))

@app.endpoint('index')
def my_index():
    return "Hello world"

© 2007–2021 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.0.x/patterns/viewdecorators/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API