Django Migrations: makemigrations and migrate addresses a recurring problem in Python projects: Version schema evolution with models and apply the same sequence in every environment. This guide explains the mechanism, provides an executable example, and identifies the boundaries that keep an implementation reliable.
Concept and use case
makemigrations compares models with migration history; migrate applies operations according to their dependency graph.
For the related fundamentals, also read the Django guide. Integration stays simpler when functions receive dependencies and data explicitly instead of relying on global state.
Practical example
python manage.py makemigrations billing --name add_invoice_status
python manage.py sqlmigrate billing 0007
python manage.py migrate --plan
python manage.py migrate
python manage.py showmigrations billing
Review files and SQL, test on representative data, and split incompatible changes into stages that old and new application versions can tolerate.
Important decisions
The correct choice depends on the public contract, expected volume, and failure behavior.
Consider concurrency, empty inputs, and partial failures. Document every limit that affects consumers and choose names that express intent.
Common mistakes
A minimal example does not replace bounds, error handling, and observability. Do not edit production tables manually or generate migrations independently there. Defaults that rewrite large tables need planning.
Avoid catching exceptions without context or returning partial output as if it were complete. An explicit failure is usually safer than silently incorrect data.
How to validate
Validate behavior, not only the happy path. Run migrate --plan, apply in staging, test reversal when supported, and confirm status with showmigrations.