## The Golden Rules 1. **Never edit a migration after it has been applied in production** 2. **Always test migrations on a staging database first** 3. **Backup before migrating** — always ## Zero-Downtime Migrations Avoid locking large tables. Instead of one destructive migration, use the expand/contract pattern: **Phase 1 (deploy):** Add the new nullable column ```python # 0042_add_column.py operations = [ migrations.AddField('MyModel', 'new_field', models.CharField(max_length=100, null=True)) ] ``` **Phase 2 (backfill):** Populate data without a migration ```bash python manage.py shell -c "MyModel.objects.filter(new_field=None).update(new_field='default')" ``` **Phase 3 (next deploy):** Make the column NOT NULL ```python migrations.AlterField('MyModel', 'new_field', models.CharField(max_length=100)) ``` ## Squashing Migrations After many iterations, squash to keep history clean: ```bash python manage.py squashmigrations website 0001 0020 ``` ## Rolling Back ```bash python manage.py migrate website 0019 # roll back to migration 19 ``` Always test rollback in staging before relying on it in production.