Feat: Add cleanup_tenant management command for improved tenant deletion

- Create new cleanup_tenant command with better tenant deletion workflow
- Handle TenantRegistration automatic processing (keep history or delete)
- Add --purge-registration flag to remove TenantRegistration records
- Add --delete-files flag to remove physical tenant files from /media/tenants/
- Provide detailed deletion summary with confirmation step
- Update УДАЛЕНИЕ_ТЕНАНТОВ.md documentation with:
  * Complete guide for new cleanup_tenant command
  * Explanation of TenantRegistration problem and solutions
  * Recommendations for different use cases (test vs production)
  * Examples of all command variants

Tested:
- Successfully deleted grach tenant (no registration)
- Successfully deleted bingo tenant with --purge-registration flag
- Verified registration records are properly managed
- All database and file operations work correctly

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-23 21:32:32 +03:00
parent 30f21989d6
commit 8079abe939
2 changed files with 632 additions and 0 deletions

View File

@@ -0,0 +1,455 @@
# Удаление Тенантов в 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
- 📖 Добавлены примеры использования для разных сценариев