Мы создали многопользовательскую платформу , используя следующую архитектуру.Я надеюсь, что вы найдете несколько полезных советов.
- Каждый арендатор получает поддомен (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
), промежуточного программного обеспечения или фабрикдля защиты представлений и выбора правильных моделей - Что касается баз данных, я использовал два разных сценария:
- Настройка нескольких баз данных и настройка маршрутизации в соответствии с текущим арендатором.Я использовал это сначала, но переключился на одну базу данных примерно через год.Причины были следующие:
- Нам не требовалось высоконадежное решение для разделения данных
- Разные арендаторы использовали практически все одинаковые модели
- Нам пришлось управлятьмного баз данных (и не было простого процесса обновления / миграции)
- Использовать одну базу данных с несколькими простыми таблицами сопоставления для пользователей и разных моделей.Чтобы добавить дополнительные и специфичные для арендатора поля модели, мы используем наследование модели .
В отношении среды мы используем следующую настройку:
С моей точки зрения, эта установка имеет следующие плюсы и минусы:
Pro:
- Один экземпляр приложения знает текущего арендатора
- Большинство частей проектане нужно беспокоиться о специфических проблемах арендаторов
- Простое решение для совместного использования сущностей всеми арендаторами (например, сообщениями)
Против:
- Один довольнобольшая база данных
- Некоторые очень похожие таблицы из-за наследования модели
- Не защищены на уровне базы данных
Конечно, лучшая архитектура сильно зависит от ваших требований, как числоарендаторов, дельта ваших моделей, требования безопасности и пр.
Обновление : Поскольку мы рассмотрели нашу архитектуру, я предлагаю , а не переписать URL, как указано в пункте 2-3.Я думаю, что лучшее решение - поместить tenant_id
в качестве заголовка запроса и извлечь (пункт 4) tenant_id
из запроса с помощью чего-то вроде request.META.get('TENANT_ID', None)
.Таким образом, вы получаете нейтральные URL-адреса, и гораздо проще использовать встроенные функции Django (например, {% url ...%}
или reverse()
) или внешние приложения.