Spec-Zone.ru › Flask 3.0

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

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

Новое в версии 0.7.

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

Почему планы?

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

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

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

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

Концепция планов

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

Мой первый план

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

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, план будет записывать намерение зарегистрировать функцию show в приложении при её последующей регистрации. Кроме того, он будет добавлять префикс к точке входа функции с именем плана, указанного в конструкторе Blueprint (в данном случае также simple_page). Имя плана не изменяет URL, только точку входа.

Регистрация планов

Как же зарегистрировать этот план? Вот так:

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 плана simple_page. Как вы видите, они также имеют префикс с именем плана, разделенные точкой (.).

Однако планы также могут быть смонтированы в разных местах:

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>])

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

Вложенные планы

Возможно зарегистрировать план в другом плане.

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

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

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

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

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, который обычно __name__. Этот аргумент указывает, какой логический модуль или пакет Python соответствует плану. Если он указывает на фактический пакет 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()

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

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

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

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

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

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

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

Шаблоны

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

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

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

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

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

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

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

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

Создание URL

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

url_for('admin.index')

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

url_for('.index')

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

Обработчики ошибок 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/3.0.x/blueprints/

Spec-Zone.ru

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