Spec-Zone.ru › Flask 3.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"

© 2010 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/3.0.x/patterns/viewdecorators/

Spec-Zone.ru

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