Форум сайта python.su
Здравствуйте.
Пишу большое приложение на Flask, используя SQLAlchemy для работы с базой. Причем приложение обслуживает несколько доменов. В связи с этим, весь функционал разделен на пакеты, которые потом регистрируются (мол “пакет - домен - префикс”).
С разделением и роутингом проблем нет, просто включила host_matching и создала новый класс на основе Blueprint. Затем просто переопределила конструктор и метод-декоратор route, чтобы каждый раз не указывать аргумент host (он будет передан конструктору и храниться как свойство класса при регистрации blueprint'ов).
Вся проблема в том, что Blueprint'ы могут регистрироваться несколько раз, причем эта регистрация по факту просто добавляет в таблицу роутинга новые маршруты. Однако импортирование в Python - это не тупой include и модули загружаются один раз и потом используются везде, где были заимпортированы. То есть, запросы у дважды зарегистрированного Blueprint'а будет обрабатывать однажды загрузившийся пакет.
Меня пока не озадачивает, что вьюхи будут одними и теми же функциями, но что делать с моделями? Они должны быть независимы для двух зарегистрированных Blueprint'ов. Мне надо как-то динамически создать для каждого Blueprint'а новую модель, наследуя эталонную? Но тогда еще надо что-то делать и со связями с другими моделями (которые могут быть так же копиями). Есть модуль copy, но это тоже магия.
Я предполагаю, что в SQLAlchemy есть какой-то механизм для решения этих проблем, но гуглинг на тему клонирования моделей особо ничего не дал. Так же может моя идея построения приложения не так хороша (по идее можно для каждого домена использовать свой экземпляр application, но пока проект не на столько большой - как-то проще не заморачиваться с их взаимодействием и использовать один).
Офлайн
О боже, какое клонирование моделей
Офлайн
aybЕсли не это, то что?
О боже, какое клонирование моделей
Отредактировано Marta (Май 1, 2016 03:03:10)
Офлайн
Модели будут одинаковыми? Или все же будут изменятся?
Офлайн
Marta
В связи с этим, весь функционал разделен на пакеты, которые потом регистрируются (мол “пакет - домен - префикс”).
Marta
С разделением и роутингом проблем нет, просто включила host_matching и создала новый класс на основе Blueprint. Затем просто переопределила конструктор и метод-декоратор route, чтобы каждый раз не указывать аргумент host (он будет передан конструктору и храниться как свойство класса при регистрации blueprint'ов).
Отредактировано 4kpt_IV (Май 1, 2016 10:04:02)
Офлайн
4kpt_IVДа. По факту надо более красивое решение, чем просто скопировать пакет под другим именем (сейчас считаю это наименее магическим путем, но не красивым). Хотя тоже: что вы конкретно понимаете под одинаковостью?
Модели будут одинаковыми? Или все же будут изменятся?
4kpt_IVМетод Flask.register_blueprint().
Подробнее. Что значит “Регистрируются”.
4kpt_IVКак-то так (этот код не запускала, но примерно такое накидывала и работало):
Тоже подробнее. Напоминает какой-то адовый овер…
class Mod(Blueprint): def __init__(self, name, import_name, static_folder=None, # чем __init__() не конструктор? static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, host=None): super().__init__(name, import_name, static_folder, static_url_path, template_folder, # py3 url_prefix, subdomain, url_defaults) self.host = host def route(self, rule, **options): def decorator(f): if 'host' not in options: options['host'] = self.host endpoint = options.pop("endpoint", f.__name__) self.add_url_rule(rule, endpoint, f, **options) return f return decorator foo = Mod('foo', __name__, host='example.org') @foo.route('/') def hi(): return 'Hi from example!' app = Flask(__name__) app.url_map.host_matching = True app.register_blueprint(foo)
Офлайн
Внимание вопрос : зачем копировать модели ?
Офлайн
Marta
Вопрос первый (Ваш). Тем, что есть еще __new__…
Вопрос второй (ayb). Да не за чем. Можно просто создавать разные БД по одним и тем же моделям по названиям blueprint, но только в том случае, если не нужно делать часто выборки по общим данным. Если же нужно, то легче создать базовую таблицу со спецификатором и по нему фильтровать, хотя я все равно склоняюсь к нескольким БД (зависит от сложность кроссбазовых запросов).
Ну и на по-следок. Таки да. Адовый хардкор. Слишком много магии. Можно значительно проще. Гляньте в сторону Flask-Classy. Там можно собирать приложение из схожих кусков, а blueprint использовать как лоток для сборки. Плюс это все дело можно наследовать и подключать под разными настройками.
Офлайн
4kpt_IV, спасибо за ответ.
4kpt_IVВозможно, вы правы и упоминать понятие конструктора в рамках Python может быть не корректно. Однако __new__() же возвращает объект класса, а __init__() его инициализирует (настраивает) - вполне себе тот же __construct из того же PHP (да и в других языках нечто подобное). Методов есть много, вплоть до перегрузки операторов при их применение к данному классу.
Тем, что есть еще __new__…
4kpt_IVИметь 20 баз под каждый Blueprint - не вариант. Можно разделять по доменам (есть же Bind в SQLAlchemy), однако это не решает вопрос двух Blueprint'ов на одном домене.
Можно просто создавать разные БД по одним и тем же моделям по названиям blueprint, но только в том случае, если не нужно делать часто выборки по общим данным.
4kpt_IVТоже думала завести дополнительные колонки в БД. Но это лишает прозрачности того, что Blueprint не думает сколько раз его подключают и как. Если бы работала с базой напрямую, составляя SQL запросы, то просто бы сделала префиксы для таблиц. Возможно, есть подобный вариант в ORM? Теоретически можно играть с маппингом…
Если же нужно, то легче создать базовую таблицу со спецификатором и по нему фильтровать, хотя я все равно склоняюсь к нескольким БД (зависит от сложность кроссбазовых запросов).
4kpt_IVДа, смотрела это расширение. Его я буду использовать, но пока разбираюсь без него с ключевыми вопросами. Оно дает гибкость, но в нем так же придется переопределить методы для введения параметра host (host matching в werkzeug - это то, что нужно, в отличии от subdomain) или форкать (что плохо. если так, то можно попробовать pull request послать). Но опять же никаких вопросов оно не снимает.
Можно значительно проще. Гляньте в сторону Flask-Classy.
Офлайн
Marta
Иметь 20 баз под каждый Blueprint - не вариант. Можно разделять по доменам (есть же Bind в SQLAlchemy), однако это не решает вопрос двух Blueprint'ов на одном домене.
Marta
Да, смотрела это расширение. Его я буду использовать, но пока разбираюсь без него с ключевыми вопросами. Оно дает гибкость, но в нем так же придется переопределить методы для введения параметра host (host matching в werkzeug - это то, что нужно, в отличии от subdomain) или форкать (что плохо. если так, то можно попробовать pull request послать). Но опять же никаких вопросов оно не снимает.
Marta
Иметь 20 баз под каждый Blueprint - не вариант. Можно разделять по доменам (есть же Bind в SQLAlchemy), однако это не решает вопрос двух Blueprint'ов на одном домене.
Marta
Тоже думала завести дополнительные колонки в БД. Но это лишает прозрачности того, что Blueprint не думает сколько раз его подключают и как.
Отредактировано 4kpt_IV (Май 5, 2016 08:12:38)
Офлайн