# Удаление Тенантов в Django-Tenants ## Быстрая справка ### Рекомендуемый способ (с улучшенной командой): ```bash # Базовое удаление (Client + БД, заявка остается в истории) python manage.py cleanup_tenant --schema=papa --noinput # Полная очистка (Client + БД + заявка + файлы) python manage.py cleanup_tenant --schema=papa --noinput --purge-registration --delete-files ``` ### Альтернативный способ (встроенная команда django-tenants): ```bash # Удалить конкретного тенанта python manage.py delete_tenant --schema=papa --noinput # Удалить все файлы тенанта (после удаления из БД) Remove-Item -Path 'media/tenants' -Recurse -Force ``` --- ## Подробное руководство ### ⭐ Способ 0: Новая улучшенная команда cleanup_tenant (РЕКОМЕНДУЕТСЯ) **Эта команда решает проблему с TenantRegistration и удаляет все в одной операции** #### Что это за команда? Это новая management команда, которая автоматически: - Удаляет Client и схему БД (как delete_tenant) - Обрабатывает TenantRegistration (может оставить в истории или удалить) - Опционально удаляет физические файлы - Показывает красивый прогресс с подтверждением #### Параметры: ```bash --schema=<имя> # Имя тенанта (обязательно) --noinput # Не запрашивать подтверждение --purge-registration # Удалить TenantRegistration (иначе оставляет с tenant=NULL) --delete-files # Удалить физические файлы из /media/tenants/ ``` #### Варианты использования: **1️⃣ Базовое удаление (рекомендуется):** ```bash python manage.py cleanup_tenant --schema=papa --noinput ``` Удаляет: Client + БД, заявка остается в истории с tenant=NULL **2️⃣ Полная очистка:** ```bash python manage.py cleanup_tenant --schema=papa --noinput --purge-registration --delete-files ``` Удаляет: Client + БД + заявка + файлы (максимальная очистка) **3️⃣ Только заявка и БД:** ```bash python manage.py cleanup_tenant --schema=papa --noinput --purge-registration ``` Удаляет: Client + БД + заявка (файлы остаются) #### Пример вывода: ``` === Удаление тенанта (магазина) === ====================================================================== ВНИМАНИЕ! Будут удалены следующие данные: ====================================================================== 📋 Тенант: • Название: Papa Shop • Schema: papa • Владелец: admin@example.com 💾 База данных: • Схема БД "papa" будет полностью удалена • Все таблицы и данные будут удалены 📝 TenantRegistration: • Заявка от Papa Owner (papa@example.com) • Статус: Одобрено • Действие: оставить с tenant=NULL (сохранить историю) ====================================================================== ▶ Начинаю удаление... ====================================================================== 1️⃣ Обновляю TenantRegistration (сохраняю историю)... ✓ TenantRegistration обновлена (tenant=NULL) 2️⃣ Удаляю Client и схему БД... ✓ Client "Papa Shop" удален ✓ Схема БД "papa" удалена ====================================================================== ✓ Тенант успешно удален! ====================================================================== ``` --- ### Способ 1: Удаление одного тенанта по schema **Команда:** ```bash cd myproject python manage.py delete_tenant --schema=papa --noinput ``` **Параметры:** - `--schema=papa` - Удалить тенант с именем schema `papa` - `--noinput` - Не запрашивать подтверждение (автоматический режим) **Результат:** ``` Deleting 'papa' Deleted 'papa' ``` Эта команда удаляет: - ✅ Схему БД тенанта - ✅ Все таблицы и данные в schema - ❌ НЕ удаляет файлы в `/media/tenants/{tenant_id}/` --- ### Способ 2: Интерактивное удаление (с выбором) **Команда:** ```bash python manage.py delete_tenant ``` **Результат:** Система запросит у вас: ``` Enter Tenant Schema ('?' to list schemas): papa Are you sure you want to delete the tenant: papa? (yes/no): yes ``` Введите: - `?` - чтобы увидеть список всех тенантов - Имя schema - чтобы выбрать тенант - `yes` - чтобы подтвердить удаление --- ### Способ 3: Удаление файлов после удаления из БД После удаления тенанта из БД нужно удалить его файлы вручную. **На Windows (PowerShell):** ```powershell Remove-Item -Path 'c:\Users\team_\Desktop\test_qwen\myproject\media\tenants' -Recurse -Force Write-Host 'Removed tenants directory' ``` **На Windows (CMD):** ```cmd rmdir /s /q "c:\Users\team_\Desktop\test_qwen\myproject\media\tenants" ``` **На Linux/Mac:** ```bash rm -rf ./media/tenants ``` --- ## Что удаляется? ### БД (удаляется автоматически): ``` PostgreSQL/MySQL schema: papa ├── products_product ├── products_productphoto ├── products_productkit ├── products_productkitphoto ├── products_productcategory ├── products_productcategoryphoto ├── inventory_* ├── orders_* └── ... (все другие таблицы в schema) ``` ### Файлы (нужно удалить вручную): ``` media/tenants/papa/ ├── products/ │ ├── {product_id}/{photo_id}/original.jpg │ ├── {product_id}/{photo_id}/large.webp │ ├── {product_id}/{photo_id}/medium.webp │ ├── {product_id}/{photo_id}/thumb.webp │ └── temp/... (временные файлы) ├── kits/ ├── categories/ └── ... (все файлы тенанта) ``` --- ## Полный цикл удаления тенанта ### 1️⃣ Удалить из БД: ```bash python manage.py delete_tenant --schema=papa --noinput ``` ### 2️⃣ Проверить оставшиеся файлы: ```powershell # На Windows Get-ChildItem -Path 'c:\Users\team_\Desktop\test_qwen\myproject\media\tenants' -Recurse | Measure-Object | Select-Object -ExpandProperty Count ``` ### 3️⃣ Удалить файлы: ```powershell # На Windows (PowerShell) Remove-Item -Path 'media/tenants' -Recurse -Force ``` ### 4️⃣ Проверить удаление: ```powershell Test-Path 'c:\Users\team_\Desktop\test_qwen\myproject\media\tenants' # Должно вернуть: False ``` --- ## Примеры ### Пример 1: Удалить тенант "papa" ```bash cd myproject python manage.py delete_tenant --schema=papa --noinput ``` ```powershell Remove-Item -Path 'media/tenants/papa' -Recurse -Force ``` ### Пример 2: Удалить все тенанты ```bash # Удалить из БД (нужно сделать для каждого тенанта) python manage.py delete_tenant --schema=papa --noinput python manage.py delete_tenant --schema=customer1 --noinput python manage.py delete_tenant --schema=test --noinput ``` ```powershell # Удалить все файлы Remove-Item -Path 'media/tenants' -Recurse -Force ``` ### Пример 3: Список доступных тенантов ```bash # Интерактивный режим - введите ? для списка python manage.py delete_tenant # Введите: ? # Получите: список всех доступных schemas ``` --- ## Важные замечания ⚠️ **ВНИМАНИЕ!** - Удаление **необратимо** - нет возможности восстановления - Сначала удаляйте из БД, потом удаляйте файлы - Не забывайте удалять файлы - они занимают место на диске - При удалении всех тенантов БД может остаться в некорректном состоянии ✅ **РЕКОМЕНДАЦИИ:** - Делайте бэкап перед удалением на продакшене - Используйте `--noinput` для автоматизации скриптами - Удаляйте файлы регулярно, чтобы освободить место - Проверяйте результат удаления --- ## Ошибки и решения ### Ошибка: "EOFError: EOF when reading a line" ``` Enter Tenant Schema ('?' to list schemas): EOFError: EOF when reading a line ``` **Решение:** Используйте флаг `--schema=` ```bash python manage.py delete_tenant --schema=papa --noinput ``` ### Ошибка: "Tenant doesn't exist" ``` Error: Tenant doesn't exist ``` **Решение:** Проверьте точное имя schema ```bash # Посмотрите список тенантов python manage.py delete_tenant # Введите: ? ``` ### Файлы не удаляются на Windows ```powershell # Если файл заблокирован, закройте все приложения и попробуйте: Remove-Item -Path 'media/tenants' -Recurse -Force -ErrorAction SilentlyContinue ``` --- ## Команда для быстрого удаления (скрипт) **delete_all_tenants.sh (для Linux/Mac):** ```bash #!/bin/bash python manage.py delete_tenant --schema=papa --noinput python manage.py delete_tenant --schema=test --noinput rm -rf ./media/tenants echo "All tenants deleted" ``` **delete_all_tenants.ps1 (для Windows):** ```powershell # Удалить БД python manage.py delete_tenant --schema=papa --noinput python manage.py delete_tenant --schema=test --noinput # Удалить файлы Remove-Item -Path 'media/tenants' -Recurse -Force -ErrorAction SilentlyContinue Write-Host "All tenants deleted successfully" ``` --- ## Что делать с TenantRegistration? ### Проблема При удалении Client тенанта остается заявка TenantRegistration со статусом 'approved' и `tenant=NULL`. Это создает проблему: если клиент захочет **повторно зарегистрироваться с тем же поддоменом**, система выдаст ошибку: ``` Error: duplicate key value violates unique constraint 'schema_name' ``` Потому что в таблице TenantRegistration уже есть запись с `schema_name='papa'`. ### Решение **Вариант 1: Оставить заявку в истории (рекомендуется)** ```bash python manage.py cleanup_tenant --schema=papa --noinput ``` Заявка остается в админке с `tenant=NULL`. Это: - ✅ Сохраняет историю регистраций - ✅ Видна попытка создания магазина (для аналитики) - ❌ Требует ручного удаления старой заявки перед новой регистрацией **Если клиент захочет зарегистрироваться снова:** 1. Вручную удалить старую TenantRegistration через админку 2. Тогда он сможет создать новую заявку с тем же schema_name **Вариант 2: Удалить заявку автоматически** ```bash python manage.py cleanup_tenant --schema=papa --noinput --purge-registration ``` Удаляет: - ✅ Client + схему БД - ✅ TenantRegistration (полная очистка) - ❌ Теряется история регистраций **Если клиент захочет зарегистрироваться снова:** 1. Просто заполняет форму регистрации 2. Может использовать тот же schema_name 3. Все работает как в первый раз ### Мой совет Для **тестового проекта**: используй `--purge-registration` (чище) ```bash python manage.py cleanup_tenant --schema=papa --noinput --purge-registration ``` Для **боевого проекта**: оставляй заявку в истории (для аудита) ```bash python manage.py cleanup_tenant --schema=papa --noinput ``` --- ## Вопросы и ответы **Q: Как посмотреть список тенантов?** A: Введите `?` в интерактивном режиме: ```bash python manage.py delete_tenant # Введите: ? ``` **Q: Могу ли я восстановить удаленного тенанта?** A: Нет, удаление необратимо. Только из бэкапа БД. **Q: Что если тенант все еще используется?** A: Появится ошибка. Закройте все приложения работающие с БД и попробуйте снова. **Q: Как удалить тенант если забыл его schema name?** A: Посмотрите в таблице `django_tenants_tenant`: ```bash python manage.py shell # Введите: from django_tenants.models import Client for tenant in Client.objects.all(): print(f"{tenant.name} -> {tenant.schema_name}") ``` --- **Дата создания:** 2025-11-23 **Дата обновления:** 2025-11-23 **Версия:** 2.0 **Статус:** Production Ready ✅ ### Что нового в версии 2.0: - ✨ Добавлена новая улучшенная команда `cleanup_tenant` - ✨ Команда автоматически обрабатывает TenantRegistration - ✨ Добавлена опция `--purge-registration` для удаления заявок - ✨ Добавлена опция `--delete-files` для удаления физических файлов - 📖 Расширена документация с объяснением проблемы TenantRegistration - 📖 Добавлены примеры использования для разных сценариев