Spec-Zone.ru › Flask 1.1

Решения при проектировании Flask

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

Явное приложение объекта

Веб-приложение Python на основе WSGI должно иметь один центральный вызываемый объект, который реализует само приложение. В Flask это экземпляр класса Flask. Каждое приложение Flask должно создавать экземпляр этого класса самостоятельно и передавать ему имя модуля. Но почему Flask не может сделать это за нас?

Без такого явного объекта приложения следующий код:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello World!'

Выглядел бы так:

from hypothetical_flask import route

@route('/')
def index():
    return 'Hello World!'

Есть три основных причины для этого. Самая важная заключается в том, что неявные объекты приложения требуют, чтобы в каждый момент времени существовал только один экземпляр. Существуют способы имитировать несколько приложений с помощью одного объекта приложения, например, поддерживая стек приложений, но это создает некоторые проблемы, которые я не буду подробно описывать здесь. Теперь вопрос в том: когда микрофреймворку нужно больше одного приложения одновременно? Хорошим примером этого является юнит-тестирование. Когда вы хотите что-то протестировать, создание минимального приложения для тестирования определенного поведения может быть очень полезным. При удалении объекта приложения все выделенные им ресурсы освобождаются.

Еще одна возможность, предоставляемая явным объектом в вашем коде, заключается в том, что вы можете наследоваться от базового класса (Flask), чтобы изменить определенное поведение. Это было бы невозможно без хакерских приёмов, если бы объект создавался заранее на основе класса, который вам недоступен.

Но есть еще одна очень важная причина, по которой Flask зависит от явного создания экземпляра этого класса: имя пакета. При создании экземпляра Flask вы обычно передаете ему __name__ в качестве имени пакета. Flask использует эту информацию для правильной загрузки ресурсов относительно вашего модуля. С помощью выдающейся поддержки Python для рефлексии он может получить доступ к пакету, чтобы определить, где хранятся шаблоны и статические файлы (см. open_resource()). Конечно, существуют фреймворки, которым не нужно никакого конфигурирования, и они всё равно смогут загружать шаблоны относительно вашего модуля приложения. Но им нужно использовать текущую рабочую директорию, что является очень ненадежным способом определения расположения приложения. Текущая рабочая директория — это глобальная переменная для всего процесса, и если вы запускаете несколько приложений в одном процессе (что может произойти в веб-сервере без вашего ведома), пути будут неверными. Хуже того, многие веб-серверы не устанавливают рабочую директорию в директорию вашего приложения, а в корневой каталог документов, который не обязательно совпадает с папкой приложения.

Третья причина — «явное лучше, чем неявное». Этот объект является вашим WSGI-приложением, вам больше ничего не нужно запоминать. Если вы хотите применить WSGI-миддлвар, просто оберните его, и всё готово (хотя существуют лучшие способы сделать это, чтобы не потерять ссылку на объект приложения wsgi_app()).

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

Система маршрутизации

Flask использует систему маршрутизации Werkzeug, разработанную для автоматического упорядочения маршрутов по сложности. Это означает, что вы можете объявлять маршруты в произвольном порядке, и они всё равно будут работать как ожидается. Это требование, если вы хотите правильно реализовать маршрутизацию на основе декораторов, так как декораторы могут вызываться в неопределённом порядке, когда приложение разбито на несколько модулей.

Еще одно решение при проектировании системы маршрутизации Werkzeug заключается в том, что маршруты в Werkzeug стараются гарантировать уникальность URL-адресов. Werkzeug сделает всё возможное, чтобы автоматически перенаправить на канонический URL-адрес, если маршрут неоднозначен.

Один движок шаблонов

Flask использует один движок шаблонов: Jinja2. Почему Flask не имеет интерфейса для подключаемых движков шаблонов? Вы можете, конечно, использовать другой движок шаблонов, но Flask всё равно сконфигурирует для вас Jinja2. Хотя это ограничение, что Jinja2 всегда сконфигурирован, вероятно, исчезнет, решение использовать один движок шаблонов и использовать его, не изменится.

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

Но это примерно всё сходство. Например, Jinja2 имеет обширную систему фильтров, определённый способ реализации наследования шаблонов, поддержку многократно используемых блоков (макросов), которые могут использоваться как внутри шаблонов, так и в коде Python, использует Unicode для всех операций, поддерживает итеративное рендеринг шаблонов, настраиваемый синтаксис и многое другое. С другой стороны, движок, подобный Genshi, основан на оценке потока XML, наследовании шаблонов с учётом доступности XPath и многом другом. Mako, в свою очередь, обрабатывает шаблоны как Python-модули.

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

Слои абстракции шаблонов, которые не отвлекались бы от уникальных особенностей движков шаблонов, — отдельная наука и задача слишком сложная для микрофреймворка, такого как Flask.

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

Микрофреймворк с зависимостями

Почему Flask называет себя микрофреймворком, но при этом зависит от двух библиотек (а именно Werkzeug и Jinja2)? Почему бы и нет? Если посмотреть на Ruby-сторону разработки веб-приложений, там у нас есть протокол, очень похожий на WSGI. Только там он называется Rack, но, помимо этого, он очень похож на WSGI-вариант для Ruby. Но почти все приложения в Ruby-среде работают не напрямую с Rack, а поверх библиотеки с тем же именем. Эта библиотека Rack имеет два аналога в Python: WebOb (ранее Paste) и Werkzeug. Paste всё ещё существует, но насколько мне известно, она устарела в пользу WebOb. Разработка WebOb и Werkzeug велась параллельно с аналогичными идеями: обеспечить хорошее исполнение WSGI для использования другими приложениями.

Flask — это фреймворк, который использует работу, уже проделанную Werkzeug, для правильного взаимодействия с WSGI (что иногда может быть сложной задачей). Благодаря недавним разработкам в инфраструктуре пакетов Python, пакеты с зависимостями больше не являются проблемой, и существуют очень немногие причины, против того, чтобы библиотеки зависели друг от друга.

Локальные переменные потоков

Flask использует локальные объекты потоков (фактически локальные объекты контекста, они также поддерживают контексты greenlet) для запроса, сессии и дополнительного объекта, на который вы можете поместить свои данные (g). Почему так, и не плохая ли это идея?

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

Также см. раздел «Развитие крупномасштабных приложений» документации (Развитие крупномасштабных приложений) для вдохновения при разработке больших приложений на основе Flask.

Что такое Flask, а что не является Flask

Flask никогда не будет иметь уровня базы данных. Он не будет иметь библиотеки форм или чего-либо подобного. Flask просто обеспечивает мост к Werkzeug для реализации правильного WSGI-приложения и к Jinja2 для обработки шаблонов. Он также связывается с некоторыми распространёнными стандартными библиотеками Python, такими как logging. Всё остальное предоставляется расширениями.

Почему это так? Потому что у людей разные предпочтения и потребности, и Flask не смог бы их удовлетворить, если бы навязывал что-либо из этого в ядро. Большинству веб-приложений потребуется движок шаблонов в той или иной форме. Однако не каждое приложение нуждается в базе данных SQL.

Идея Flask состоит в том, чтобы создать хорошую основу для всех приложений. Всё остальное зависит от вас или расширений.

© 2007–2020 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/1.0.x/design/

Spec-Zone.ru

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