Spec-Zone.ru › Flask 2.1

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

В 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–2022 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.1.x/patterns/viewdecorators/

Spec-Zone.ru

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