Модульные приложения с 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 , например, в случае, если текущий запрос был направлен на любую другую точку входа admin blueprint.
Обработчики ошибок 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
© 2007–2022 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.3.x/blueprints/