Keeping your models in sync with your migrations is an important part of any Django app. My team and I frequently make changes to our models and we occassionally forget to create new migrations for those changes. This results in errors and data loss. Let’s look at an easy way to ensure your models and migrations are always in sync:
We’ll use a simple
class Product(models.Model): name = models.CharField(max_length=255)
Let’s say we want to add a
class Product(models.Model): name = models.CharField(max_length=255) quantity = models.PositiveIntegerField(default=1)
At this point, we should create a new migration using
python3 manage.py makemigrations. However, let’s say we forget, which is a common mistake, and we attempt to create a new product. This results in an error and the data is never added to the database.
In : from core.models import Product In : Product.objects.create(name="Headphones", quantity=3) # OperationalError: table core_product has no column named quantity
It would be ideal to catch this bug earlier in the development cycle. We can do this using the
--check flag on the
makemigrations command, which will “Exit with a non-zero status if model changes are missing migrations”.
$ python3 manage.py makemigrations --dry-run --check # Migrations for 'core': # core/migrations/0002_product_quantity.py # - Add field quantity to product $ echo $? # 1
--dry-run prevents the migrations from actually being created and
echo $? prints the exit code of the last run command. As we can see from the output and the non-zero exit code, we’re missing migrations.
We can automatically run this check before committing to version control using the popular pre-commit framework.
# .pre-commit-config.yaml repos: - repo: local hooks: - id: check-django-migrations name: Check django migrations entry: python3 manage.py makemigrations --dry-run --check language: system types: [python] # hook only runs if a python file is staged pass_filenames: false
If we try to commit, we’ll get an error.
$ git commit -m "Add quantity field to Product model" # Check django migrations..................................................Failed # - hook id: check-django-migrations # - exit code: 1 # # Migrations for 'core': # core/migrations/0002_product_quantity.py # - Add field quantity to product
Only after we create the required migration files will the check pass and the commit will go through.
$ git commit -m "Add quantity field to Product model" # Check django migrations..................................................Passed
May your models always be in sync with your migrations.