Handling Django migrations in multiple git branches

Within a Django project with separate development and production branches sharing a common database, how do developers manage divergent database schema changes between branches to ensure smooth deployment and rollback procedures? Specifically, how do you handle situations where changes introduced in the development branch might potentially disrupt features or stability in the production branch, and what strategies or best practices do you employ to mitigate risks and maintain database integrity during deployment and rollback processes?

1 Like

I can’t speak for anyone else or any other group, but I can describe what we do.

Every developer is responsible for merging from master to their branch before merging their branch back into master.

We maintain a “staging” system where master gets deployed to, to test everything before it goes to production. Once it’s tested in staging, then a production deployment is schedule. Our production deployment process backs up the database, deploys the code, runs migrate and collectstatic, starts the system and runs a set of site tests.

I wrote a package that helps here a bit, django-linear-migrations: Introducing django-linear-migrations - Adam Johnson

Ensuring the smooth deployment of migrations will always be a tricky process. Some operations lock a whole table, so they’re fine at one scale and disastrous at another. I haven’t seen any great general solution there.

I ran into this exact problem in my local dev env when switching frequently between branches with diverging django migrations (mainly dev and main branches), so I wrote a bash script to automate the migrations rollback/migrate.

In a nutshell, it:

  • Compares migrations between the current and target branches
  • Rolls back apps to the last common migration if they diverge (works also when migrations have been merged between branches, see the script for details)
  • Switches branches
  • Applies the appropriate migrations for the new branch

Once set up as a git alias, you can just run git pswitch <branch-name>

Gist link to the script

Open to any feedback or ideas to make it better!

In my opinion, sharing a common database between your staging and production environment is not the right approach. Instead, I would run two separate databases, one for staging and one for production. Whenever you deploy a new version to your staging environment, I would drop the staging database and create a fresh copy from the production the database. By doing so, the table `django_migrations` is resetted and you can deploy as often to stanging as you want until everything works fine.

This has the advantage that you can always test if your migrations run smoothly and you never risk to drop an important column or worse.