Migration rollback vs. backup restore after a failed Django upgrade: managing --fake divergence
0 reputation · 10 May 2024, 23:04 UTC
0 reputation · 10 May 2024, 23:04 UTC
Determine the preferred recovery path when a Django upgrade fails and the migration recorder no longer matches the actual database schema.
Rolling back with migrate only works if every intervening migration is reversible; non‑reversible RunPython steps block this route. Using migrate --fake can realign the recorder but does not undo partial schema changes already applied by the database, risking schema drift. Restoring a pre‑upgrade backup guarantees a consistent state but incurs downtime and may lose transactions committed after the backup snapshot. The trade‑off is further complicated by cross‑app migration dependencies and third‑party migrations that may lack reverse code (assume Django 4.2/5.0 behavior).
RunPython operations affect the choice between rollback and backup restore?35275 reputation · 11 May 2024, 05:33 UTC
Restore from the pre-upgrade backup. That is the only path that guarantees the migration recorder and the live schema agree after a failed Django upgrade. Use migrate --fake only when you can confirm no schema-altering SQL committed during the failure; otherwise it hides drift instead of removing it.
Likely explanation: The upgrade applied some migrations, then stopped at a migration containing RunPython without reverse_code. Django's recorder is now out of sync with the actual tables, columns, and constraints.
Confirmed facts for Django 4.2 and 5.0:
migrate can roll back only through migrations where every operation defines a reverse step.RunPython without reverse_code is non-reversible and blocks rollback past that migration.migrate --fake writes to django_migrations without issuing schema SQL, so it cannot undo partial DDL already applied to the database.django_migrations against the migration files in your upgraded codebase.python manage.py migrate --fake app_label migration_name for the exact failed migration, then run python manage.py migrate to apply remaining migrations.python manage.py showmigrations and confirm every migration marked applied has matching tables, columns, and constraints in the database.python manage.py inspectdb and diff its output against your model definitions to detect missing or extra schema objects.Did the failed upgrade commit any DDL before failing, or did the database roll back the migration transaction? This determines whether --fake is safe or whether backup restore is mandatory.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 11 May 2024, 10:05 UTC
Using --fake only rewrites django_migrations; it never undoes DDL that the database already executed. Therefore you can only fake when the live schema already matches the target state. Before faking, compare the live tables with the migration’s SQL via python manage.py sqlmigrate app migration and a schema‑only dump. If the schema differs, a backup restore is the lower‑drift path.
After a restore, run python manage.py migrate --plan to verify that the migration graph is coherent and that no irreversible RunPython blocks remain. This two‑step check helps avoid drift when dependencies or third‑party migrations lack reverse code.