Разрабатываю большое Flask приложение, возникла проблема в его архитектуре. В целом то мне понравился подход в
https://github.com/sean-/flask-skeleton, что можно использовать Blueprint (так то подобных примеров и гайдов полно).
Однако приложение большое тем, что оно не просто разбито на несколько файлов для удобства, а обслуживает несколько сайтов (хостов/поддоменов - будет задаваться в конфиге), которые имеют пересечение функционала (следовательно, есть общий код для этого) и между ними поддерживается общая сессия пользователя и сама база с ними (и некоторыми другими данными).
В целом то архитектура построена сейчас таким образом, что есть некоторое ядро, где созданы общие модели, классы для всех сайтов, а так же создается приложение Flask, подключено расширение Flask-SQLAlchemy. Так же было включена поддержка host matching и реализовано указание хоста в Blueprint. Сами же блоки функционала хранятся в индивидуальных пакетах, где создается Blueprint'ы под это дело, определены формы, модели (они импортируют из ядра созданный объект класса SQLAlchemy из расширения), вьюхи. В целом, задумка такая же, как и в указанном скелетоне.
Казалось бы все хорошо, регистрируй Блюпринты в приложении Flask и радуйся. Но проблема в том, что Blueprint по факту просто регистрирует в таблице роутинга одни и те же импортированными вьюхи под разными маршрутами (предполагается регистрация одного Блюпринта множество раз - Flask это позволяет). И даже не в этом корень проблемы: модель то в блоке функционала остается той же самой и работает с теми же самыми данными. По факту по разным адресам будет одно и то же, что сводит весь смысл в приложении на нет.
Сначала пытался решить проблему с моделями, но начал задумываться: а правильно ли была построена архитектура приложения? Не слишком ли требовать от Blueprint'а и пакетов питона полной изоляции? Возможно, надо двигаться в сторону создания конкретных экземпляров моделей из абстрактной и подсовывать это в вьюху через паттерн DI? Возможно, вовсе стоит уже сейчас прибегнуть к паттерну фабрики приложения и создавать Flask приложение для каждого сайта (но тогда надо прокидывать сессию и прочие общности между ними)?
Если кратко и на пальцах, то хотелось бы построить архитектуру, где пускай есть site1.ru, site2.ru, site3.ru. Базы пользователей и регистрация у них общая, сессия тоже. Имеется общий код в виде блоков, который пускай реализуют функционал тех же новостей, статей и форумов. И в конфиге бы указывалось, что на site1.ru нужны новости на главном (префикс /), на site2.ru нужно два каталога статей (префиксы /articles_1/ и /articles_2/), на site3.ru нужны новости (префикс /news/) и форум (префикс /forum/). И, понятное дело, что эти, так сказать, блоки кода должны оперировать с разным контентом.
Ну и отвечу на некоторые возможные вопросы:
- Flask выбран потому, что он минималистичен и позволяет гибко строить приложения (да, расплата за это то, что необходимо местами делать связки и строить архитектуру самостоятельно. но гибкость, минималистичность, мощность я ценю
- Django не выбрал потому, что она удобна скорее для типовых решений. мне не все нравится как в ней устроено, пришлось бы так же переписывать и реализовывать некоторые вещи
- Да, мои знания в Python не идеальны, но мне нравится погружаться в нечто новое с помощью реальных проектов, а не вызубривать тонны книжек перед этим или строя очередной учебный мироклон твиттера, где описанные проблемы просто не поднимаются
- Внутренности работы SQLAlchemy мне до конца не ясны пока, но мне начинает казаться, что надо воевать не с ней, а в архитектуре просто допущен косяк, почему все и выходит так...
P.S. Извиняюсь за столь длинную портянку, но хотелось бы решить проблему красиво, так как бьюсь над ней уже некоторое время. А решать колхозом вроде складывания всего контента всего в одну модель (точнее таблицу, так как на нее модель мапится) - не хотелось бы. Если бы не было ORM, то в чистом SQL решилось бы простыми префиксами у таблиц. Но ORM, Python - это для меня пока новый стек технологий, которые очень бы хотелось уже использовать, а не сидеть в php4-style.