Перейти к содержанию

Механизм IBP Proxy

Приложение planiqum.apps.ibp — это динамический прокси-модуль, который обеспечивает прозрачное переключение между различными реализациями IBP (Integrated Business Planning) в проекте.

Введение

В ядре Planiqum часто требуется обращаться к моделям, представлениям или скриптам, специфичным для конкретной инсталляции IBP (например, ibp0, ibp1). Чтобы избежать жесткой привязки к конкретному приложению в коде ядра (например, import planiqum.apps.ibp1), используется промежуточный слой — planiqum.apps.ibp.

Этот слой перенаправляет все обращения (импорты, вызовы атрибутов) к "текущему" активному модулю IBP, который задается в настройках.

Как это работает

Механизм реализован в файле src/planiqum/apps/ibp.py и базируется на подмене модуля в sys.modules.

1. Настройка MODULE_IBP

В файле конфигурации (settings.py или config.conf) задается переменная MODULE_IBP. Она содержит имя реального модуля, который должен использоваться в данный момент.

Пример:

# settings.py
MODULE_IBP = "ibp1"  # или "ibp0", "ibp_demo" и т.д.

2. Класс IBPProxyModule

Этот класс наследуется от types.ModuleType и переопределяет поведение доступа к атрибутам.

class IBPProxyModule(ModuleType):
    def __init__(self, name, real_module):
        # ... инициализация ...
        self._real_module = real_module
        # Копирование атрибутов реального модуля в прокси
        for attr_name in dir(real_module):
            if not attr_name.startswith("_"):
                setattr(self, attr_name, getattr(real_module, attr_name))

    def __getattr__(self, name):
        # Перехват обращений к подмодулям (models, views и т.д.)
        if name in ["models", "views", "urls", "forms", "serializers", ...]:
            # Динамический импорт из реального модуля
            full_name = f"planiqum.apps.{MODULE_IBP}.{name}"
            module = importlib.import_module(full_name)
            # Кэширование и возврат
            return module

        # Делегирование остальных атрибутов реальному модулю
        return getattr(self._real_module, name)

3. Подмена модуля (Monkey Patching)

В конце файла src/planiqum/apps/ibp.py происходит магия:

_real_module = importlib.import_module(f"planiqum.apps.{MODULE_IBP}")
new_module = IBPProxyModule("planiqum.apps.ibp", _real_module)
sys.modules["planiqum.apps.ibp"] = new_module

Благодаря этому, когда любой другой код выполняет import planiqum.apps.ibp, Python возвращает экземпляр IBPProxyModule, который уже "настроен" на работу с ibp1 (или другим выбранным модулем).

Как использовать

Правильные импорты

Всегда импортируйте IBP через прокси-модуль planiqum.apps.ibp.

Правильно:

from planiqum.apps.ibp import models as ibp_models
from planiqum.apps.ibp.views import some_view

Неправильно (в коде ядра):

from planiqum.apps.ibp1 import models as ibp_models  # Жесткая привязка!

Использование в миграциях

В миграциях Django часто используется apps.get_model. Прокси-механизм работает и здесь, так как INSTALLED_APPS будет содержать planiqum.apps.ibp (если так настроено), но чаще всего IBP приложения добавляются в INSTALLED_APPS динамически или явно.

Однако, для доступа к моделям IBP из кода, не зависящего от конкретной реализации, используйте прокси.

Создание новой реализации IBP

Чтобы создать новую версию IBP (например, ibp2):

  1. Создайте директорию src/planiqum/apps/ibp2.
  2. Добавьте __init__.py.
  3. Реализуйте стандартную структуру Django-приложения (models.py, views.py, urls.py).
  4. В настройках сервера измените MODULE_IBP на ibp2.
  5. Перезапустите сервер. Теперь from planiqum.apps.ibp import ... будет работать с кодом из ibp2.

Ограничения

  1. IDE и статический анализ: PyCharm/VS Code могут не видеть атрибуты внутри planiqum.apps.ibp, так как они разрешаются динамически. Это нормально.
  2. Циклические импорты: Будьте осторожны при импорте planiqum.apps.ibp внутри самого ibpX. Это может привести к рекурсии или циклическому импорту. Обычно модуль реализации (ibp1) не должен знать о существовании прокси.

Важно: описанные настройки и сценарии могут отличаться в вашей инсталляции Planiqum
За уточнениями и методологической поддержкой обращайтесь в компанию ЮНИК СОФТ