Skip to content

Instantly share code, notes, and snippets.

@majackson
Created June 9, 2017 13:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save majackson/16a05aa873efab2a12eb648e6c1fe6f9 to your computer and use it in GitHub Desktop.
Save majackson/16a05aa873efab2a12eb648e6c1fe6f9 to your computer and use it in GitHub Desktop.

Django Migrations without Downtime

Note that in the below instructions, migrations are all run manually and are not an automatic part of the deployment process.

Adding Fields or Tables

Adding a (nullable) field or a new table

  1. Make the model or column addition in your code.
  2. Generate the model-change migrations locally.
  3. Make two separate pull requests, one containing the model change, one containing the newly-generated migrationst. Note that the model-change migration should only contain the model change code, not any supplemental code using the newly-structured model.
  4. Merge and deploy the migration pull request.
  5. Run the new migration on the production database. Additional fields in the production database will not cause any problems if the production model code is not expecting them to be there.
  6. Merge the model-change pull request.
  7. Deploy the code with the model change. It will now seamlessly start reading from the previously created column/table.

Adding a NOT NULL field

In order to add a NOT NULL field, you should first add a nullable field with the steps above, then follow the following additional steps:

  1. Make the model change to null=False. Also ensure your code never inserts or updates None values into the field you are converting to NOT NULL.
  2. Generate the migration for this change.
  3. Make two separate pull requests for these changes: one for the models, one for the migration.
  4. Merge the code change pull request.
  5. Merge the migration pull request.
  6. Run the migration on the production database.

Notes on adding NOT NULL columns in very large tables

Django migrations will insist on a default value when making a NOT NULL field. This value is used to populate empty columns during hte migration. This update process will lock the postgres table for writes until it has completed. For relatively small tables (<100,000 rows), this is probably fine. For exceptionally large tables though, this could be a problem, because the locked tables could prevent requests from executing while the migration completes. For this reason, consider making new fields nullable in especially large tables (and to a lesser extent in all tables). This may have a cost to your application code, but is probably optimal in comparison to failing to respond to requests.

Removing Fields or Tables

Removing a nullable field or a table

Essentially, this is the same as adding, but with the steps in a slightly different order.

  1. Remove all usages of the model or column to be deleted from your application code.
  2. Deploy a version of the code which still has the model/column to be deleted present, but not used by any of the code.
  3. Make the model or column removal in your application code.
  4. Generate the removal migration.
  5. Merge the model change pull request.
  6. Deploy the code with the model changes. Ensure there are no errors resulting from lingering references to what is being deleted.
  7. Merge the migration pull request.
  8. Deploy the code with the migration.
  9. Explicitly run the migration on the production database.

Removing a NOT NULL field

In order to remove a NOT NULL field, you first need to migrate it to a nullable field, then follow the steps above to remove a nullable field. The steps to convert a NOT NULL field to a nullable field are:

  1. Set your field's model to null=True
  2. Generate your migration for this change.
  3. Make two separate pull requests: one with the model-change, one with the migration change.
  4. Merge and deploy the migration pull request.
  5. Run the migration on the production database.
  6. Merge and deploy your model change code.

After following these steps, follow the steps above to remove the nullable field.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment