Skip to content

Commit 92b26da

Browse files
committed
improve docs for cols
1 parent 4762d48 commit 92b26da

File tree

1 file changed

+51
-13
lines changed
  • develop-docs/api-server/application-domains/database-migrations

1 file changed

+51
-13
lines changed

develop-docs/api-server/application-domains/database-migrations/index.mdx

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,53 @@ class TestModel(Model):
170170
db_table = "uptime_testmodel"
171171
```
172172

173-
First we remove the constraint and make the column nullable:
173+
First, we remove all references to this field from the codebase. This is best done as a separate pr to keep things clean.
174+
175+
Next we produce two migrations, in individual prs that we will deploy separately.
176+
177+
First PR
178+
```python
179+
# <Field removed from model and code completely>
180+
181+
# First migration
182+
# ... Migration boilerplate ...
183+
operations = [
184+
migrations.AlterField(
185+
model_name="testmodel",
186+
name="project",
187+
field=sentry.db.models.fields.foreignkey.FlexibleForeignKey(
188+
db_constraint=False,
189+
null=True,
190+
on_delete=django.db.models.deletion.CASCADE,
191+
to="sentry.project",
192+
),
193+
),
194+
SafeRemoveField(model_name="testmodel", name="project", deletion_action=DeletionAction.MOVE_TO_PENDING),
195+
]
196+
# ... Migration boilerplate ...
197+
```
198+
199+
Second PR:
200+
```python
201+
# Second migration
202+
# ... Migration boilerplate ...
203+
operations = [
204+
SafeRemoveField(model_name="testmodel", name="project", deletion_action=DeletionAction.DELETE),
205+
]
206+
# ... Migration boilerplate ...
207+
```
208+
209+
So once we have these two prs, we merge/deploy the first, and then the second and then the table is fully removed.
210+
211+
So to recap the steps here:
212+
- Remove all references to the column in the code in a separate pull request and merge. Doesn't matter if this deploys before the next step or not.
213+
- If the column has a foreign key constraint them remove it. If it's not null and has no `db_default` then mark it as nullable. Then delete the column using `SafeRemoveField(..., deletion_action=DeletionAction.MOVE_TO_PENDING)`. These operations can be in the same migration to save time.
214+
- Deploy all previous before continuing.
215+
- Remove the column from the table in from Postgres using `SafeRemoveField(..., deletion_action=DeletionAction.DELETE),`
216+
217+
If you're comfortable producing these prs and deploying them, then stop here. Otherwise, this next section covers how to produce them in more detail.
218+
219+
To produce the first migration, we need to remove the db level foreign key constraint, make the column nullable and remove the column from the codebase. To remove the db level foreign key constraints and mark the column nullable we add `db_constraint=False, null=True` to this column and generate a migration:
174220

175221
```python
176222
# Model change
@@ -201,15 +247,15 @@ operations = [
201247
]
202248
```
203249

204-
Deleting this way is unsafe, so we want to replace this with `SafeDeleteModel` instead. So this becomes
250+
Django doesn't know about the `SafeRemoveField` operation, so we replace it with that instead. This allows us to remove all state related to the column, but defer deleting it until a later migration. So this becomes
205251

206252
```python
207253
operations = [
208254
SafeRemoveField(model_name="testmodel", name="project", deletion_action=DeletionAction.MOVE_TO_PENDING),
209255
]
210256
```
211257

212-
Using `SafeRemoveField` allows us to remove all the state related to the column, but defer deleting it until a later migration. So now, we can combine the migration to remove the constraints and delete the column state together like so
258+
So now as a final step, we can combine these operations into a single migration, which is the first migration we want to deploy.
213259

214260
```python
215261
operations = [
@@ -227,22 +273,14 @@ operations = [
227273
]
228274
```
229275

230-
So now we deploy this migration and move onto the final step.
231-
232-
In this last step, we will use `SafeRemoveField` again to finally remove the column from the table in Postgres. First, we generate an empty migration using `sentry django makemigrations <your_app> --empty` to produce an empty migration, and then modify the operations to be like:
276+
To produce the second migration we generate an empty migration (`sentry django makemigrations <your_app> --empty`), then use the same `SafeRemoveField` command from the previous migration, but change the deletion_action to `DeletionAction.DELETE`. This operation will remove the column from the table in Postgres:
233277

234278
```python
235279
operations = [
236280
SafeRemoveField(model_name="testmodel", name="project", deletion_action=DeletionAction.DELETE),
237281
]
238282
```
239283

240-
Then we deploy this and we're done. So to recap the steps here:
241-
- Remove all references to the column in the code in a separate pull request and merge. Doesn't matter if this deploys before the next step or not.
242-
- If the column has an foreign key constraint them remove it. If it's not null and has no `db_default` then mark it as nullable. Then delete the column using `SafeRemoveField(..., deletion_action=DeletionAction.MOVE_TO_PENDING)`. These operations can be in the same migration to save time.
243-
- Deploy all previous before continuing.
244-
- Remove the column from the table in from Postgres using `SafeRemoveField(..., deletion_action=DeletionAction.DELETE),`
245-
246284
### Deleting Tables
247285

248286
Extra care is needed here if the table is referenced as a foreign key in other tables. In that case, first remove the foreign key columns in the other tables, then come back to this step.
@@ -315,7 +353,7 @@ So to recap the steps here:
315353

316354
If you're comfortable producing these prs and deploying them, then stop here. Otherwise, this next section covers how to produce them in more detail.
317355

318-
To produce the first migration, we need to remove any db level foreign key constraints and remove the table from the codebase. To remove the db level foreign key constraints we add `db_constraint` to this column and generate a migration:
356+
To produce the first migration, we need to remove any db level foreign key constraints and remove the table from the codebase. To remove the db level foreign key constraints we add `db_constraint=False` to this column and generate a migration:
319357

320358
```python
321359
project = FlexibleForeignKey("sentry.Project", db_constraint=False)

0 commit comments

Comments
 (0)