Ответ 1
Мы построили платформу с использованием следующей архитектуры. Надеюсь, вы найдете полезные подсказки.
- Каждый арендатор получает субдомен (t1.example.com)
- Использование url-переписывания запросов для приложения Django переписывается на что-то вроде example.com/t1
- Все определения url имеют префикс с чем-то вроде
(r'^(?P<tenant_id>[\w\-]+)
- A middleware обрабатывает и потребляет tenant_id и добавляет его в запрос (например, request.tenant = 't1')
- Теперь у вас есть текущий арендатор, доступный в каждом представлении без указания аргумента tenant_id для каждого представления
- В некоторых случаях у вас нет запроса. Я решил эту проблему, привязывая tenant_id к текущему потоку (аналогично текущему языку, используя
threading.local
) - Создайте декораторы (например, осведомленные арендаторы
login_required
), посредники или фабрики для защиты представлений и выбора правильных моделей. - Что касается баз данных, я использовал два разных сценария:
- Настройка нескольких баз данных и настройка routing в соответствии с текущим арендатором. Я использовал это сначала, но через один год переключился на одну базу данных. Причины были следующие:
- Нам не нужно высокое безопасное решение для разделения данных
- Различные арендаторы использовали практически все те же модели
- Нам пришлось управлять множеством баз данных (и не создавал простой процесс обновления/переноса)
- Используйте одну базу данных с некоторыми простыми таблицами сопоставления для пользователей и разных моделей. Чтобы добавить дополнительные и специализированные поля модели, мы используем наследование модели.
- Настройка нескольких баз данных и настройка routing в соответствии с текущим арендатором. Я использовал это сначала, но через один год переключился на одну базу данных. Причины были следующие:
Что касается среды, мы используем следующую настройку:
С моей точки зрения, эта настройка имеет следующие pro и con:
Pro:
- Один экземпляр приложения, зная текущего арендатора
- Большинство частей проекта не должны беспокоиться о конкретных проблемах с арендатором.
- Простое решение для обмена объектами между всеми арендаторами (например, сообщениями)
Contra:
- Одна довольно большая база данных
- Некоторые очень похожие таблицы из-за наследования модели
- Не защищен на уровне базы данных
Конечно, лучшая архитектура сильно зависит от ваших требований как количества арендаторов, дельта ваших моделей, требований безопасности и т.д.
Обновление. Когда мы рассмотрели нашу архитектуру, я предлагаю не переписывать URL-адрес, как указано в пункте 2-3. Я считаю, что лучшим решением является размещение tenant_id
в качестве заголовка запроса и извлечение (точка 4) tenant_id
из запроса с чем-то вроде request.META.get('TENANT_ID', None)
. Таким образом, вы получаете нейтральные URL-адреса, и гораздо проще использовать встроенные функции Django (например, {% url ...%}
или reverse()
) или внешние приложения.