Catching missing migrations in Django
Jan 29, 2017 10:41 · 272 words · 2 minutes read
Automation is the key to catching this.
In Django the rules of what does and does not require a migration seem entirely arbitrary to me in. For starters I always forget that verbose_name
requires one. Then at some point down the road, I discover that I have missed a migration in a earlier commit. I then need to get my git-foo on to tidy things up. Here is how I use automation to solve this issue.
A little help from makemigrations
I run this in my CI environment in Django 1.9.
$ ./manage.py makemigrations --dry-run --no-input | grep 'No changes detected' || exit 1
--dry-run
prints what it will do.--no-input
skips the stale content types input prompt.
Then I grep for the “No changes detected” string in the output, if it isn’t, I exit 1
.
Once I make the move to Django 1.10, things become even easier with the new --check
option on makemigrations
:
$ ./manage.py makemigrations --check --dry-run
This exits with a non-zero error code if there are outstanding migrations. [docs]
CI or as a Unit Test?
If this is a major concern you can run this as a unit test (pytest example):
import pytest
from django.core.management import call_command
def test_no_missing_migrations():
with pytest.raises(SystemExit) as e:
call_command(
'makemigrations',
interactive=False,
check=True,
dry_run=True,
)
assert str(e.value) == '1'
Personally, I did not want to run this check when running my tests, the call to makemigrations
is somewhat slow (in my case 8 seconds) and my project test suite is still small and fast with only taking 3-4 seconds. I did not want to triple my test suite runtime just for this check.