1.makemigrations, migrate, and the dependency graph
makemigrations compares current models against migration history and WRITES a new migration file describing the difference — it never touches the database. migrate READS migration files and actually APPLIES (or unapplies) them against the real database. Each migration file lists dependencies (which other migrations must run first) and operations (what to actually do) — Django builds an in-memory graph from every app's dependencies to compute one consistent apply order. Two developers each adding a migration on the same base, in parallel branches, produces a CONFLICT — makemigrations --merge resolves it by creating one migration depending on both.
Key features
- makemigrations never touches the database — it only reads models.py and writes a migration file; migrate is the step that actually executes SQL
- A migration file has two key parts: dependencies (a list of (app, migration_name) tuples that must apply first) and operations (the actual CreateModel/AddField/etc. instructions)
- Django builds one in-memory graph from every app's migrations combined — a migration can depend on a migration from a COMPLETELY DIFFERENT app, which is how cross-app ForeignKeys stay correctly ordered
- A migration conflict happens when two migrations in the same app both declare the SAME migration as their dependency (e.g. two developers both branched off 0002 and each created their own 0003) — Django refuses to proceed until it is resolved
- makemigrations --merge creates a new migration whose dependencies list BOTH conflicting migrations, linearizing the history into one valid graph again
makemigrations vs migrate
- models.py — current model definitions
- leads to makemigrations
- makemigrations — diffs against migration history — no DB touched
- leads to 0003_add_rating.py
- 0003_add_rating.py — dependencies + operations
- leads to migrate
- migrate — reads the file, applies it
- leads to database schema
- database schema
Command
class Migration(migrations.Migration):
dependencies = [("books", "0002_previous_migration")]
operations = [migrations.AddField("Book", "rating", models.IntegerField(default=0))]makemigrations writes a migration file from a models.py diff (no database touched); migrate reads migration files and actually applies them. A migration's dependencies (which can cross app boundaries) plus every app's combined graph determine one consistent apply order. A conflict (two migrations claiming the same dependency) is resolved with makemigrations --merge, not by deleting a file.