Реализована полноценная система мультитенантности на базе django-tenants. Каждый магазин получает изолированную схему БД и поддомен. Основные компоненты: Django-tenants интеграция: - Модели Client (тенант) и Domain в приложении tenants/ - Разделение на SHARED_APPS и TENANT_APPS - Public schema для общей админки - Tenant schemas для изолированных данных магазинов Система регистрации магазинов: - Публичная форма регистрации на /register/ - Модель TenantRegistration для заявок со статусами (pending/approved/rejected) - Валидация schema_name (латиница, 3-63 символа, уникальность) - Проверка на зарезервированные имена (admin, api, www и т.д.) - Админ-панель для модерации заявок с кнопками активации/отклонения Система подписок: - Модель Subscription с планами (триал 90 дней, месяц, квартал, год) - Автоматическое создание триальной подписки при активации - Методы is_expired() и days_left() для проверки статуса - Цветовая индикация в админке (зеленый/оранжевый/красный) Приложения: - tenants/ - управление тенантами, регистрация, подписки - shops/ - точки магазинов/самовывоза (tenant app) - Обновлены миграции для всех приложений Утилиты: - switch_to_tenant.py - переключение между схемами тенантов - Обновлены image_processor и image_service Конфигурация: - urls_public.py - роуты для public schema (админка + регистрация) - urls.py - роуты для tenant schemas (магазины) - requirements.txt - добавлены django-tenants, django-environ, phonenumber-field Документация: - DJANGO_TENANTS_SETUP.md - настройка мультитенантности - TENANT_REGISTRATION_GUIDE.md - руководство по регистрации - QUICK_START.md - быстрый старт - START_HERE.md - общая документация Использование: 1. Пользователь: http://localhost:8000/register/ → заполняет форму 2. Админ: http://localhost:8000/admin/ → активирует заявку 3. Результат: http://{schema_name}.localhost:8000/ - готовый магазин 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
303 lines
9.2 KiB
Markdown
303 lines
9.2 KiB
Markdown
# Настройка Django Tenants для multi-tenancy
|
||
|
||
Этот проект настроен как SaaS-платформа с поддержкой multi-tenancy через django-tenants.
|
||
Каждый владелец магазина получает свой поддомен и изолированную схему БД в PostgreSQL.
|
||
|
||
## Шаг 1: Установка PostgreSQL
|
||
|
||
### Вариант A: Установка локально (Windows)
|
||
|
||
1. Скачайте PostgreSQL с https://www.postgresql.org/download/windows/
|
||
2. Установите PostgreSQL (запомните пароль для пользователя `postgres`)
|
||
3. Откройте pgAdmin или psql и создайте базу данных:
|
||
|
||
```sql
|
||
CREATE DATABASE inventory_db;
|
||
```
|
||
|
||
### Вариант B: Использование Docker (рекомендуется)
|
||
|
||
```bash
|
||
docker run --name inventory-postgres \
|
||
-e POSTGRES_PASSWORD=postgres \
|
||
-e POSTGRES_DB=inventory_db \
|
||
-p 5432:5432 \
|
||
-d postgres:15
|
||
```
|
||
|
||
## Шаг 2: Установка зависимостей
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
Это установит:
|
||
- `django-tenants==3.7.0`
|
||
- `psycopg2-binary==2.9.10`
|
||
- и другие зависимости
|
||
|
||
## Шаг 3: Настройка подключения к БД
|
||
|
||
Откройте `myproject/settings.py` и при необходимости измените параметры подключения:
|
||
|
||
```python
|
||
DATABASES = {
|
||
'default': {
|
||
'ENGINE': 'django_tenants.postgresql_backend',
|
||
'NAME': 'inventory_db',
|
||
'USER': 'postgres',
|
||
'PASSWORD': 'postgres', # ВАШ ПАРОЛЬ
|
||
'HOST': 'localhost',
|
||
'PORT': '5432',
|
||
}
|
||
}
|
||
```
|
||
|
||
## Шаг 4: Создание миграций
|
||
|
||
```bash
|
||
# Создать миграции для всех приложений
|
||
python manage.py makemigrations
|
||
|
||
# Применить миграции для public схемы
|
||
python manage.py migrate_schemas --shared
|
||
```
|
||
|
||
## Шаг 5: Создание публичного тенанта
|
||
|
||
Django-tenants требует создания public тенанта для работы главного домена (inventory.by):
|
||
|
||
```bash
|
||
python manage.py shell
|
||
```
|
||
|
||
```python
|
||
from tenants.models import Client, Domain
|
||
|
||
# Создать public тенанта
|
||
public_tenant = Client.objects.create(
|
||
schema_name='public',
|
||
name='Главный домен',
|
||
owner_email='admin@inventory.by',
|
||
owner_name='Администратор'
|
||
)
|
||
|
||
# Создать домен для public
|
||
public_domain = Domain.objects.create(
|
||
domain='localhost', # Для локальной разработки
|
||
tenant=public_tenant,
|
||
is_primary=True
|
||
)
|
||
|
||
print(f'Public тенант создан: {public_tenant}')
|
||
print(f'Public домен создан: {public_domain}')
|
||
exit()
|
||
```
|
||
|
||
## Шаг 6: Создание суперпользователя
|
||
|
||
```bash
|
||
# Создать суперпользователя в public схеме
|
||
python manage.py createsuperuser --schema=public
|
||
```
|
||
|
||
Введите:
|
||
- Email: ваш email
|
||
- Name: ваше имя
|
||
- Password: ваш пароль
|
||
|
||
## Шаг 7: Создание тестового магазина (тенанта)
|
||
|
||
```bash
|
||
python manage.py create_tenant
|
||
```
|
||
|
||
Введите данные:
|
||
- Название магазина: Тестовый Магазин
|
||
- Схема БД: shop1
|
||
- Домен: shop1.localhost (или оставьте по умолчанию)
|
||
- Имя владельца: Иван Иванов
|
||
- Email: shop1@example.com
|
||
- Телефон: (опционально)
|
||
|
||
Команда автоматически:
|
||
1. Создаст тенанта в таблице `Client`
|
||
2. Создаст домен в таблице `Domain`
|
||
3. Создаст схему БД `shop1` в PostgreSQL
|
||
4. Применит все миграции к схеме `shop1`
|
||
|
||
## Шаг 8: Настройка hosts файла
|
||
|
||
Для локального тестирования добавьте в файл hosts:
|
||
|
||
**Windows**: `C:\Windows\System32\drivers\etc\hosts`
|
||
**Linux/Mac**: `/etc/hosts`
|
||
|
||
```
|
||
127.0.0.1 localhost
|
||
127.0.0.1 shop1.localhost
|
||
127.0.0.1 shop2.localhost
|
||
```
|
||
|
||
## Шаг 9: Запуск сервера
|
||
|
||
```bash
|
||
python manage.py runserver 0.0.0.0:8000
|
||
```
|
||
|
||
## Шаг 10: Тестирование
|
||
|
||
### Доступ к админке супер-администратора (Public схема):
|
||
- URL: http://localhost:8000/admin/
|
||
- Логин: email и пароль суперпользователя
|
||
- Здесь вы можете управлять тенантами (магазинами)
|
||
|
||
### Доступ к админке магазина (Tenant схема):
|
||
- URL: http://shop1.localhost:8000/admin/
|
||
- Создайте суперпользователя для магазина:
|
||
```bash
|
||
python manage.py tenant_command createsuperuser --schema=shop1
|
||
```
|
||
- Здесь владелец магазина управляет своими товарами, заказами, клиентами
|
||
|
||
---
|
||
|
||
## Архитектура проекта
|
||
|
||
### Public Schema (схема `public`):
|
||
Доступна по адресу: `localhost` или `inventory.by`
|
||
|
||
**Модели:**
|
||
- `Client` - информация о тенантах (магазинах)
|
||
- `Domain` - домены тенантов
|
||
|
||
**Кто имеет доступ:**
|
||
- Супер-администратор (вы)
|
||
|
||
**Для чего:**
|
||
- Управление тенантами
|
||
- Просмотр статистики
|
||
- Биллинг (в будущем)
|
||
|
||
### Tenant Schema (схемы `shop1`, `shop2`, и т.д.):
|
||
Доступна по поддоменам: `shop1.localhost`, `shop2.localhost`
|
||
|
||
**Модели:**
|
||
- `Customer` - клиенты магазина
|
||
- `Address` - адреса клиентов
|
||
- `Shop` - точки магазина
|
||
- `Product`, `ProductKit`, `Category` - товары
|
||
- `Order`, `OrderItem` - заказы
|
||
- `Inventory` - складской учет
|
||
- `CustomUser` - сотрудники (для будущего)
|
||
|
||
**Кто имеет доступ:**
|
||
- Владелец магазина
|
||
- Сотрудники магазина (в будущем)
|
||
|
||
**Для чего:**
|
||
- Управление товарами
|
||
- Обработка заказов
|
||
- Работа с клиентами
|
||
- Складской учет
|
||
|
||
---
|
||
|
||
## Полезные команды
|
||
|
||
### Создать тенанта:
|
||
```bash
|
||
python manage.py create_tenant
|
||
```
|
||
|
||
### Применить миграции ко всем тенантам:
|
||
```bash
|
||
python manage.py migrate_schemas
|
||
```
|
||
|
||
### Применить миграции только к public:
|
||
```bash
|
||
python manage.py migrate_schemas --shared
|
||
```
|
||
|
||
### Применить миграции к конкретному тенанту:
|
||
```bash
|
||
python manage.py migrate_schemas --schema=shop1
|
||
```
|
||
|
||
### Выполнить команду для конкретного тенанта:
|
||
```bash
|
||
python manage.py tenant_command <command> --schema=shop1
|
||
```
|
||
|
||
Например:
|
||
```bash
|
||
python manage.py tenant_command createsuperuser --schema=shop1
|
||
python manage.py tenant_command loaddata data.json --schema=shop1
|
||
```
|
||
|
||
### Список всех тенантов:
|
||
```bash
|
||
python manage.py shell
|
||
```
|
||
```python
|
||
from tenants.models import Client
|
||
for tenant in Client.objects.all():
|
||
print(f'{tenant.name}: {tenant.schema_name}')
|
||
```
|
||
|
||
---
|
||
|
||
## Устранение проблем
|
||
|
||
### Ошибка: "No tenant found for hostname"
|
||
- Проверьте, что домен добавлен в hosts файл
|
||
- Проверьте, что домен существует в таблице `Domain`
|
||
- Проверьте, что вы обращаетесь к правильному поддомену
|
||
|
||
### Ошибка: "relation does not exist"
|
||
- Запустите миграции: `python manage.py migrate_schemas`
|
||
- Проверьте, что схема создана в PostgreSQL
|
||
|
||
### Ошибка подключения к PostgreSQL:
|
||
- Проверьте, что PostgreSQL запущен
|
||
- Проверьте параметры подключения в `settings.py`
|
||
- Проверьте, что база данных `inventory_db` существует
|
||
|
||
---
|
||
|
||
## Продакшн
|
||
|
||
Для продакшна (на сервере):
|
||
|
||
1. Измените `settings.py`:
|
||
```python
|
||
DEBUG = False
|
||
ALLOWED_HOSTS = ['.inventory.by']
|
||
```
|
||
|
||
2. Настройте DNS для поддоменов (wildcard):
|
||
```
|
||
*.inventory.by → ваш сервер
|
||
```
|
||
|
||
3. Используйте реальные домены вместо localhost
|
||
|
||
4. Настройте PostgreSQL с безопасным паролем
|
||
|
||
5. Используйте environment variables для секретов
|
||
|
||
---
|
||
|
||
## Следующие шаги
|
||
|
||
После успешной настройки:
|
||
|
||
1. ✅ Создайте несколько тестовых магазинов
|
||
2. ✅ Добавьте товары в каждый магазин
|
||
3. ✅ Создайте тестовые заказы
|
||
4. ✅ Проверьте изоляцию данных между магазинами
|
||
5. 🔜 Разработайте веб-интерфейс для владельцев магазинов
|
||
6. 🔜 Добавьте регистрацию новых магазинов через веб-форму
|
||
7. 🔜 Реализуйте биллинг и тарифные планы
|