# SM014: rename_model

| Property       | Value         |
| -------------- | ------------- |
| **Rule ID**    | SM014         |
| **Severity**   | WARNING       |
| **Name**       | rename_model  |
| **Applies to** | All databases |

## What Triggers This Rule

This rule triggers when a migration contains `RenameModel`:

```python
# Triggers SM014
migrations.RenameModel(
    old_name='Customer',
    new_name='Client',
)
```

## Why It's Dangerous

Renaming a model/table has far-reaching effects:

1. **Foreign keys break** — Tables referencing this model need updates
2. **Code references break** — All imports, queries, serializers fail
3. **External systems break** — APIs, reports, integrations fail
4. **ORM assumptions break** — Django expects specific table names

### Additional Concerns

- **Django ContentTypes** — The content type record has the old model name
- **Generic Foreign Keys** — References use content type + object ID
- **Permissions** — Django permission names include the model name
- **Admin URLs** — Admin URLs include the model name
- **Database constraints** — Constraint names may reference the table

### Real-World Failure Scenario

```
Timeline (rolling deployment):
├─ 0:00  Migration runs → table renamed from customer to client
├─ 0:01  Server 1 (old code): SELECT * FROM customer
├─ 0:01  Database: ERROR - relation "customer" does not exist
├─ 0:01  User sees 500 error
├─ ...
├─ 0:05  Server 1 gets new code
├─ 0:05  ContentType still says "customer"
├─ 0:06  Generic FK lookups fail
└─ ...   Cascading issues continue
```

## When It's Safe to Ignore

This warning can be safely ignored when:

1. **Using blue-green deployment** — Complete cutover, no rolling update
2. **Maintenance mode enabled** — No traffic during deployment
3. **No foreign keys reference this model** — Isolated table
4. **No generic FKs point to this model** — Not used in ContentTypes

## How to Fix It

### Option 1: Use db_table (Recommended)

Keep the old table name in the database but use a new model name in code:

```python
# In models.py
class Client(models.Model):
    name = models.CharField(max_length=100)

    class Meta:
        db_table = 'myapp_customer'  # Keep old table name
```

No migration needed for this change!

### Option 2: Create New Model and Migrate Data

If you need a new table name:

**Step 1: Create new model**

```python
class Client(models.Model):
    name = models.CharField(max_length=100)
    # Copy of all fields from Customer
```

**Step 2: Copy data**

```python
def migrate_customers_to_clients(apps, schema_editor):
    Customer = apps.get_model('myapp', 'Customer')
    Client = apps.get_model('myapp', 'Client')

    for customer in Customer.objects.all():
        Client.objects.create(
            id=customer.id,
            name=customer.name,
            # ... all fields
        )

migrations.RunPython(migrate_customers_to_clients, migrations.RunPython.noop)
```

**Step 3: Update foreign keys**

```python
# For each model with FK to Customer
migrations.AddField(
    model_name='order',
    name='client',
    field=models.ForeignKey('myapp.Client', null=True, on_delete=models.CASCADE),
)

# Migrate FK data
def migrate_fks(apps, schema_editor):
    Order = apps.get_model('myapp', 'Order')
    Order.objects.all().update(client_id=models.F('customer_id'))

migrations.RunPython(migrate_fks, migrations.RunPython.noop)
```

**Step 4: Update code, deploy**

**Step 5: Remove old model and FK**

```python
migrations.RemoveField(model_name='order', name='customer')
migrations.DeleteModel(name='Customer')
```

### Update ContentTypes (If Needed)

```python
def update_content_type(apps, schema_editor):
    ContentType = apps.get_model('contenttypes', 'ContentType')
    ContentType.objects.filter(
        app_label='myapp',
        model='customer'
    ).update(model='client')

migrations.RunPython(update_content_type, migrations.RunPython.noop)
```

## How to Suppress

### In Django Settings

```python
SAFE_MIGRATIONS = {
    "DISABLED_RULES": ["SM014"],
}
```

## See Also

- [SM006: rename_column](SM006.md) — Similar rule for renaming columns
- [SM002: drop_column_unsafe](SM002.md) — Related to removing model fields
- [SM003: drop_table_unsafe](SM003.md) — Related to removing models
