Spec-Zone.ru › Flask 0.12

Решения по проектированию в 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, чтобы обрабатывать шаблоны. Он также связан с несколькими распространёнными пакетами стандартной библиотеки, такими как logging. Всё остальное предоставляется для расширений.

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

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

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

Spec-Zone.ru

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