From 9dc6d56ee67ee14abe39bcedd097ce7d10b1809e Mon Sep 17 00:00:00 2001 From: Dan Fuller Date: Tue, 19 Nov 2024 09:37:17 -0800 Subject: [PATCH 1/2] Update index.mdx --- .../database-migrations/index.mdx | 31 ++----------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/develop-docs/api-server/application-domains/database-migrations/index.mdx b/develop-docs/api-server/application-domains/database-migrations/index.mdx index 2233d884d210a..ce94926f6d749 100644 --- a/develop-docs/api-server/application-domains/database-migrations/index.mdx +++ b/develop-docs/api-server/application-domains/database-migrations/index.mdx @@ -313,36 +313,9 @@ creating new columns they should either be: ### Adding Columns With a Default -We run Postgres 14 in production. This means that we can now safely add columns with a default without worrying about rewriting the table. We still need to be careful though. +Since we run Postgres >= 14 in production we are able to add columns with a default. To do so, instead of using `default=`, instead use `db_default=`. This tells Django to set a default at the database level and manage it there, rather than managing it in code. -Django's default behaviour for creating a new not null column with a default is dangerous. When adding a default, in the migrations Django will add the default to backfill all fields, then immediately remove it so that it can handle them in the app layer. This means that during a deploy, the column is sitting in production without a default until all code rolls out. This means that inserts will fail for this table until the deploy completes. - -To work around this, you can tell your migration to leave the default in place in Postgres. - -```python - operations = [ - migrations.SeparateDatabaseAndState( - database_operations=[ - migrations.RunSQL( - """ - ALTER TABLE "sentry_groupedmessage" ADD COLUMN "type" integer NOT NULL DEFAULT 1; - """, - reverse_sql=""" - ALTER TABLE "sentry_groupedmessage" DROP COLUMN "type"; - """, - hints={"tables": ["sentry_groupedmessage"]}, - ), - ], - state_operations=[ - migrations.AddField( - model_name="group", - name="type", - field=sentry.db.models.fields.bounded.BoundedPositiveIntegerField(default=1), - ), - ], - ) - ] -``` +We can't use `default` because Django's default behaviour for creating a new not null column with a default is dangerous. When using default, in the migration Django will add the default to backfill all fields, then immediately remove it so that it can handle them in the app layer. This means that during a deploy, the column is sitting in production without a default until all code rolls out, which means that inserts will fail for this table until the deploy completes. ### Adding Not Null To Columns From 14e983713af83bb9fdf1603ba746a71399220ac8 Mon Sep 17 00:00:00 2001 From: Dan Fuller Date: Tue, 19 Nov 2024 09:39:29 -0800 Subject: [PATCH 2/2] Update index.mdx --- .../application-domains/database-migrations/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/develop-docs/api-server/application-domains/database-migrations/index.mdx b/develop-docs/api-server/application-domains/database-migrations/index.mdx index ce94926f6d749..4fb8d707513cd 100644 --- a/develop-docs/api-server/application-domains/database-migrations/index.mdx +++ b/develop-docs/api-server/application-domains/database-migrations/index.mdx @@ -313,7 +313,7 @@ creating new columns they should either be: ### Adding Columns With a Default -Since we run Postgres >= 14 in production we are able to add columns with a default. To do so, instead of using `default=`, instead use `db_default=`. This tells Django to set a default at the database level and manage it there, rather than managing it in code. +Since we run Postgres >= 14 in production we are able to add columns with a default. To do so, instead of using `default=`, use `db_default=`. This tells Django to set a default at the database level and manage it there, rather than managing it in application code. We can't use `default` because Django's default behaviour for creating a new not null column with a default is dangerous. When using default, in the migration Django will add the default to backfill all fields, then immediately remove it so that it can handle them in the app layer. This means that during a deploy, the column is sitting in production without a default until all code rolls out, which means that inserts will fail for this table until the deploy completes.