Debugging migrations: the graph and the data
A migration bug is a deployment bug: it is discovered at the worst moment, on the machine you cannot experiment on. The skill this section trains is bringing the failure back to your own machine, by reproducing the exact starting state the migration ran on.
Migrations are a graph, and the numbers are decoration
Each migration lists its dependencies; the file number is only a naming convention. Two migrations that depend on the same parent are two leaf nodes, and migrate refuses to choose an order. Learn to read the graph (showmigrations, the dependencies list at the top of each file) rather than the file names, and to fix a fork by merging it, not by deleting files that may already have been applied somewhere.
Reproduce the starting state, not just the code
A migration is a function of the schema and the data it meets. It can pass on an empty database and on staging and still fail on production because production has NULLs, duplicates and legacy values nobody remembers. To debug it, recreate that starting state: migrate a scratch database back to the migration before the failing one, insert rows shaped like production, then migrate forward and read the actual error.
Expand, backfill, constrain
The safe shape for adding a required or unique column is three steps: add it nullable (expand), fill it with values that satisfy the future constraint by construction (backfill), then tighten it (constrain). Most migration failures on real data are a backfill that assumed the data was clean. Keep migrations reversible where you can, keep the model and the migrations in agreement (makemigrations --check in CI), and never weaken the model just to make a deploy pass.