Django Migrations
By ILLIA
Django Migrations
Introduction
Migrations are used by Django to track and push changes in models (creating/deleting a model, adding a field, etc.) to the database. Here are four essential commands that are used when working with database migrations:
makemigrations
– is used to create new migrations based on changes made in database models.migrate
– is used to apply and revert existing migrations.sqlmigrate
– is used to display SQL statement based on migration.showmigrations
– is used to list projects migrations and their status.
makemigrations
and migrate
commands are the most essential commands. Migration files are located in the migrations directory of each app. Any changes in models require the creation of new migrations.
The basic workflow after creating or modifying models with sample output:
$ python manage.py makemigrations
Sample output
Migrations for 'pets':
pets/migrations/0002_auto.py:
- Alter field owner on pet
$ python manage.py migrate
Sample output
Operations to perform:
Apply all migrations: pets
Running migrations:
Rendering model states... DONE
Applying pets.0002_auto... OK
Dependencies
When creating a migration for one app that relates to a model from another app (e.g. app pets requires a ForeignKey from owners table), this migration will be created with a dependency on the migration of the second app. This means that migrations from app 2 should run before migrations from app 1, which are dependent on them. Essentially, this is the way to tell Django to run something else before running this migration.
Migration files
Migration file contains a class that extends django.db.migrations.Migration class and have 4 attributes, 2 of those are the most used:
- dependencies – is a list of migrations that current migration depends on
- operations – a list of Operation classes that define what this migration does
A basic migration file looks like this:
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('pets', '0001_initial'),
]
operations = [
migrations.RenameField(
model_name='pet',
old_name='owners',
new_name='owner',
),
]
Operations are most essential because they are a set of declarative instructions that specify what changes in the database schema have to be made.
Migration can have initial = True
attribute which shows that this migration is the initial one. Initial migration is the one that creates the first version of apps database tables.
Migrations are used by Django to track and push changes in models (creating/deleting a model, adding a field, etc.) to the database.
History consistency
Inconsistent migration history is when migration has been applied but some of its dependencies have not. This is a strong indication that the dependencies are incorrect, so Django will not run these migrations or make new migrations until this issue has been fixed.
Reversing migrations
These two commands are used to reverse the migrations that have already been applied:
python manage.py migrate
– migrates app to the specified migration. If the app is ahead of this migration, then the command would reverse all migrations back to this point. Otherwise, if the app is behind this migration, then the previous migrations will be applied up until this migration. Usage and sample output:$ python manage.py migrate pets 0002 Operations to perform: Target specific migration: 0002_auto, from pets Running migrations: Rendering model states... DONE Unapplying pets.0003_auto... OK
python manage.py migrate
– reverses all migrations. Usage and sample output:zero $ python manage.py migrate pets zero Operations to perform: Unapply all migrations: pets Running migrations: Rendering model states... DONE Unapplying pets.0002_auto... OK Unapplying pets.0001_initial... OK
Squashing migrations
You can create as many migrations as you want; however, the project can become very messy with a lot of migration files that may contain actions that neutralize each other (e.g. add a field in one migration, remove that field in another). In order to prevent this, migrations can be squashed and the new migration will apply all changes created in previous migrations. Here is a command to do it:
python manage.py squashmigrations
Usage and sample output:
$ ./manage.py squashmigrations pets 0004
Will squash the following migrations:
- 0001_initial
- 0002_some_change
- 0003_another_change
- 0004_undo_something
Do you wish to proceed? [y/N] y
Optimizing...
Optimized from 12 operations to 7 operations.
Created new squashed migration /home/bob/Programs/DjangoTest/test/migrations/0001_squashed_0004_undo_somthing.py
You should commit this migration but leave the old ones in place;
the new migration will be used for new installs. Once you are sure
all instances of the codebase have applied the migrations you squashed,
you can delete them.
Steps to do after you squashed migrations:
- Commit the new squashed migration with all other migrations it replaces :white_check_mark:
- Delete all migration files that were replaced with a new one :white_check_mark:
- Update all dependent migrations to use the new squashed one :white_check_mark:
- Remove replaces attribute in Migration class of the squashed migration :white_check_mark:
- Commit these changes :white_check_mark:
For more information, please visit Django Documentation.