A migration is a small Python file that describes a change to the database schema — "add this column," "drop this index," "rename this table." Migrations are committed source code: anyone running python manage.py migrate replays the migrations they haven't applied yet, in order, and ends up with the same schema as you.
Two commands matter:
makemigrations — diffs your models against the previous migration state and writes a new migration file. It does not touch the database.migrate — applies pending migrations to the database.The mental model: your models.py is the desired state; the migration files are the change history that gets the database from one state to the next. Django tracks which migrations have run in the django_migrations table.
The most common Django footgun: editing models.py and forgetting to run makemigrations. The code looks right, the model is "updated," but the database has no idea. Tests using --keepdb will mask it.
This PR added four fields to UserFeed. Running makemigrations produced 0014_userfeed_scheduling_fields.py, which contains a list of migrations.AddField(...) operations. That file is committed alongside the model change — they always travel together.
operations = [
migrations.AddField(
model_name="userfeed",
name="next_check_at",
field=models.DateTimeField(blank=True, db_index=True, null=True),
),
...
]
0014_userfeed_scheduling_fields.py and match each AddField to the corresponding line in models.py. Note that default="" shows up in the operation but db_index=True becomes its own CREATE INDEX step.
Done when: you can describe what SQL Django will run for each operation.makemigrations, look at the file, then delete the field, delete the migration file, and re-run makemigrations to see Django produce nothing. (Don't migrate it.) Get a feel for the diff-based generation.
Done when: you've watched the migration file appear and disappear in response to model changes.RunPython — find a migration in this repo or another Django project that uses migrations.RunPython. That's how data migrations (not just schema) are expressed.
Done when: you can name the difference between a schema migration (AddField, AlterField) and a data migration (RunPython, RunSQL).