Spec-Zone.ru › Flask 2.3

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

В 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 с формы входа. Это можно сделать с помощью скрытого тега input, а затем извлечь его из 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.3.x/patterns/viewdecorators/

Spec-Zone.ru

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