Files
octopus/УДАЛЕНИЕ_ТЕНАНТОВ.md
Andrey Smakotin 8079abe939 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>
2025-11-23 21:32:32 +03:00

456 lines
15 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Удаление Тенантов в 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
- 📖 Добавлены примеры использования для разных сценариев