Spec-Zone.ru › Flask

Модульные приложения с Blueprints

Журнал изменений

Добавлен в версии 0.7.

Flask использует концепцию blueprints для создания компонентов приложения и поддержки общих шаблонов внутри приложения или между приложениями. Blueprints значительно упрощают работу с большими приложениями и предоставляют централизованный способ для расширений Flask регистрировать операции в приложениях. Объект Blueprint работает аналогично объекту приложения Flask, но на самом деле не является приложением. Скорее это blueprint (шаблон), описывающий, как построить или расширить приложение.

Почему Blueprints?

Blueprints в Flask предназначены для следующих случаев:

  • Разбиение приложения на набор blueprints. Это идеально подходит для крупных приложений; проект может создать объект приложения, инициализировать несколько расширений и зарегистрировать набор blueprints.
  • Регистрация blueprint в приложении с префиксом URL и/или доменным именем. Параметры в префиксе URL/доменном имени становятся общими аргументами представления (с значениями по умолчанию) для всех функций представления в blueprint.
  • Регистрация одного blueprint несколько раз в приложении с различными правилами URL.
  • Предоставление фильтров шаблонов, статических файлов, шаблонов и других утилит через blueprints. Blueprint не обязательно должен реализовывать приложения или функции представлений.
  • Регистрация blueprint в приложении в любом из этих случаев при инициализации расширения Flask.

Blueprint в Flask не является подключаемым приложением, так как он на самом деле не является приложением – это набор операций, которые можно зарегистрировать в приложении, даже несколько раз. Зачем не использовать несколько объектов приложения? Вы можете сделать это (см. Переключение приложений), но ваши приложения будут иметь отдельные конфигурации и будут управляться на уровне WSGI.

Blueprints вместо этого обеспечивают разделение на уровне Flask, совместно используют конфигурацию приложения и могут изменять объект приложения по мере необходимости при регистрации. Недостатком является то, что вы не можете отменить регистрацию blueprint после создания приложения, не уничтожив весь объект приложения.

Концепция Blueprints

Основная концепция blueprints заключается в том, что они записывают операции, которые должны быть выполнены при регистрации в приложении. Flask связывает функции представлений с blueprints при обработке запросов и генерации URL от одной точки входа к другой.

Мой первый Blueprint

Вот что выглядит очень базовый blueprint. В данном случае мы хотим реализовать blueprint, который выполняет простое отображение статических шаблонов:

from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound

simple_page = Blueprint('simple_page', __name__,
                        template_folder='templates')

@simple_page.route('/', defaults={'page': 'index'})
@simple_page.route('/<page>')
def show(page):
    try:
        return render_template(f'pages/{page}.html')
    except TemplateNotFound:
        abort(404)

Когда вы связываете функцию с помощью декоратора @simple_page.route, blueprint будет записывать намерение зарегистрировать функцию show в приложении при последующей регистрации. Кроме того, он добавит префикс к точке входа функции с именем blueprint, которое было передано конструктору Blueprint (в данном случае также simple_page). Имя blueprint не изменяет URL, а только точку входа.

Регистрация Blueprints

Итак, как зарегистрировать этот blueprint? Вот так:

from flask import Flask
from yourapplication.simple_page import simple_page

app = Flask(__name__)
app.register_blueprint(simple_page)

Если вы проверите зарегистрированные правила в приложении, вы найдете следующие:

>>> app.url_map
Map([<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
 <Rule '/<page>' (HEAD, OPTIONS, GET) -> simple_page.show>,
 <Rule '/' (HEAD, OPTIONS, GET) -> simple_page.show>])

Первый, очевидно, из самого приложения для статических файлов. Другие два – для функции show blueprint simple_page. Как видите, они также имеют префикс с именем blueprint и разделены точкой (.).

Однако blueprints также могут быть подключены к различным местоположениям:

app.register_blueprint(simple_page, url_prefix='/pages')

И, конечно же, вот сгенерированные правила:

>>> app.url_map
Map([<Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
 <Rule '/pages/<page>' (HEAD, OPTIONS, GET) -> simple_page.show>,
 <Rule '/pages/' (HEAD, OPTIONS, GET) -> simple_page.show>])

Кроме того, вы можете зарегистрировать blueprints несколько раз, хотя не каждый blueprint может должным образом реагировать на это. Фактически, это зависит от реализации blueprint, может ли он быть подключен более чем один раз.

Вложенные Blueprints

Можно зарегистрировать blueprint в другом blueprint.

parent = Blueprint('parent', __name__, url_prefix='/parent')
child = Blueprint('child', __name__, url_prefix='/child')
parent.register_blueprint(child)
app.register_blueprint(parent)

Вложенный blueprint получит имя родительского blueprint в качестве префикса к своему имени, а дочерние URL будут иметь префикс URL родительского blueprint.

url_for('parent.child.create')
/parent/child/create

Кроме того, вложенный blueprint получит поддомен родительского blueprint, с поддоменом в качестве префикса, если он есть, например:

parent = Blueprint('parent', __name__, subdomain='parent')
child = Blueprint('child', __name__, subdomain='child')
parent.register_blueprint(child)
app.register_blueprint(parent)

url_for('parent.child.create', _external=True)
"child.parent.domain.tld"

Функции до обработки запроса, специфичные для blueprint, и т.д., зарегистрированные в родительском blueprint, будут вызываться для дочернего. Если у дочернего blueprint нет обработчика ошибок, который может обработать данную ошибку, будет пробоваться обработчик родительского blueprint.

Ресурсы Blueprint

Blueprints также могут предоставлять ресурсы. Иногда вам может потребоваться ввести blueprint только для предоставления ресурсов.

Папка ресурсов Blueprint

Как и для обычных приложений, blueprints предполагается, что они содержатся в папке. Хотя несколько blueprints могут исходить из одной папки, это необязательно, и это обычно не рекомендуется.

Папка определяется из второго аргумента Blueprint, который обычно равен __name__. Этот аргумент указывает, какой логический модуль Python или пакет соответствует blueprint. Если он указывает на фактический Python-пакет, пакет (который является папкой в файловой системе) будет папкой ресурсов. Если это модуль, пакет, в котором содержится модуль, будет папкой ресурсов. Вы можете получить доступ к свойству Blueprint.root_path, чтобы увидеть папку ресурсов:

>>> simple_page.root_path
'/Users/username/TestProject/yourapplication'

Для быстрого открытия источников из этой папки вы можете использовать функцию open_resource():

with simple_page.open_resource('static/style.css') as f:
    code = f.read()

Статические файлы

Blueprint может экспонировать папку со статическими файлами, предоставив путь к папке в файловой системе с помощью аргумента static_folder. Это может быть абсолютный путь или относительный путь к расположению blueprint:

admin = Blueprint('admin', __name__, static_folder='static')

По умолчанию правая часть пути – это то место, где она экспонируется в веб-приложении. Это можно изменить с помощью аргумента static_url_path. Поскольку папка называется static здесь, она будет доступна по адресу url_prefix blueprint + /static. Если у blueprint есть префикс /admin, статический URL будет /admin/static.

Точка входа называется blueprint_name.static. Вы можете генерировать URL-адреса к нему с помощью url_for(), как вы это делаете со статической папкой приложения:

url_for('admin.static', filename='style.css')

Однако, если у blueprint нет url_prefix, доступ к статической папке blueprint недоступен. Это потому, что URL будет /static в этом случае, и маршрут приложения /static имеет приоритет. В отличие от папок шаблонов, статические папки blueprint не проверяются, если файл не существует в статической папке приложения.

Шаблоны

Если вы хотите, чтобы blueprint экспонировал шаблоны, вы можете сделать это, предоставив параметр template_folder конструктору Blueprint:

admin = Blueprint('admin', __name__, template_folder='templates')

Для статических файлов путь может быть абсолютным или относительным к папке ресурсов blueprint.

Папка шаблонов добавляется в путь поиска шаблонов, но имеет более низкий приоритет, чем собственная папка шаблонов приложения. Таким образом, вы можете легко переопределить шаблоны, предоставляемые blueprint, в фактическом приложении. Это также означает, что если вы не хотите, чтобы шаблон blueprint случайно переопределялся, убедитесь, что ни у одного другого blueprint или шаблона приложения нет такого же относительного пути. Когда несколько blueprints предоставляют один и тот же относительный путь к шаблону, первый зарегистрированный blueprint имеет приоритет над другими.

Итак, если у вас есть blueprint в папке yourapplication/admin и вы хотите отобразить шаблон 'admin/index.html' и вы предоставили templates как template_folder, вам нужно создать файл, похожий на этот: yourapplication/admin/templates/admin/index.html. Причина дополнительной папки admin – избежать переопределения шаблона шаблоном index.html в фактической папке шаблонов приложения.

Для дальнейшего уточнения: если у вас есть blueprint под названием admin и вы хотите отобразить шаблон index.html, специфичный для этого blueprint, лучше всего расположить ваши шаблоны следующим образом:

yourpackage/
    blueprints/
        admin/
            templates/
                admin/
                    index.html
            __init__.py

А затем, когда вы захотите отобразить шаблон, используйте admin/index.html в качестве имени для поиска шаблона. Если у вас возникают проблемы с загрузкой правильных шаблонов, включите переменную конфигурации EXPLAIN_TEMPLATE_LOADING, которая будет указывать Flask на печать шагов, которые он выполняет для поиска шаблонов в каждом вызове render_template.

Создание URL-адресов

Если вы хотите создать ссылку с одной страницы на другую, вы можете использовать функцию url_for(), как обычно, но вы добавляете префикс к точке входа URL с именем blueprint и точкой (.):

url_for('admin.index')

Кроме того, если вы находитесь в функции представления blueprint или в рендерном шаблоне и хотите создать ссылку на другую точку входа того же blueprint, вы можете использовать относительные перенаправления, добавив префикс точки входа только с точкой:

url_for('.index')

Это будет ссылка на admin.index например, в случае, если текущий запрос был передан в любой другой blueprint администратора.

END_OF_DOCUMENT_MARKER

Обработчики ошибок Blueprint

Blueprints поддерживают декоратор errorhandler так же, как и объект приложения Flask, поэтому легко создавать страницы ошибок, специфичные для Blueprint.

Вот пример для исключения «404 Страница не найдена»:

@simple_page.errorhandler(404)
def page_not_found(e):
    return render_template('pages/404.html')

Большинство обработчиков ошибок будут работать как ожидается; однако есть оговорка относительно обработчиков для исключений 404 и 405. Эти обработчики вызываются только из соответствующего raise оператора или вызова abort в другой функции представления blueprint; они не вызываются, например, при доступе к недопустимому URL. Это связано с тем, что blueprint не «владеет» определенным пространством URL, поэтому экземпляр приложения не знает, какой обработчик ошибок blueprint следует запустить, если предоставлен недопустимый URL. Если вы хотите выполнить различные стратегии обработки для этих ошибок на основе префиксов URL, они могут быть определены на уровне приложения с помощью объекта прокси request:

@app.errorhandler(404)
@app.errorhandler(405)
def _handle_api_error(ex):
    if request.path.startswith('/api/'):
        return jsonify(error=str(ex)), ex.code
    else:
        return ex

См. Обработка ошибок приложения.

© 2010 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/stable/blueprints/

Spec-Zone.ru

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