Модульные приложения с 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('pages/%s.html' % page)
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)
Если проверить зарегистрированные правила на приложении, вы найдете следующие:
[<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')
И, конечно же, вот сгенерированные правила:
[<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
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 например, в случае, если текущий запрос был направлен в какую-либо другую точку входа admin 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(ex)
else:
return ex
Дополнительную информацию об обработке ошибок см. в Настраиваемые страницы ошибок.
© 2007–2020 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/1.0.x/blueprints/