Skip to content

Commit 73bebc1

Browse files
authored
feat(dashboards): Make organizations non-nullable (#93033)
This is a follow up to #92272 where I added the column as nullable and a backfill PR to update preexisting models. New instances are always created with the organization, and I've run the backfill PR across all deployments. Closes DAIN-535
1 parent ddbcf41 commit 73bebc1

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

migrations_lockfile.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ preprod: 0001_emerge_upload_models
2323

2424
replays: 0001_squashed_0005_drop_replay_index
2525

26-
sentry: 0923_dashboard_starred_backfill_orgs
26+
sentry: 0924_dashboard_add_unique_constraint_for_user_org_position
2727

2828
social_auth: 0001_squashed_0002_default_auto_field
2929

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Generated by Django 5.2.1 on 2025-06-06 15:48
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
import sentry.db.models.fields.foreignkey
7+
from sentry.new_migrations.migrations import CheckedMigration
8+
9+
10+
class Migration(CheckedMigration):
11+
# This flag is used to mark that a migration shouldn't be automatically run in production.
12+
# This should only be used for operations where it's safe to run the migration after your
13+
# code has deployed. So this should not be used for most operations that alter the schema
14+
# of a table.
15+
# Here are some things that make sense to mark as post deployment:
16+
# - Large data migrations. Typically we want these to be run manually so that they can be
17+
# monitored and not block the deploy for a long period of time while they run.
18+
# - Adding indexes to large tables. Since this can take a long time, we'd generally prefer to
19+
# run this outside deployments so that we don't block them. Note that while adding an index
20+
# is a schema change, it's completely safe to run the operation after the code has deployed.
21+
# Once deployed, run these manually via: https://develop.sentry.dev/database-migrations/#migration-deployment
22+
23+
is_post_deployment = False
24+
25+
dependencies = [
26+
("sentry", "0923_dashboard_starred_backfill_orgs"),
27+
]
28+
29+
operations = [
30+
migrations.AlterField(
31+
model_name="dashboardfavoriteuser",
32+
name="organization",
33+
field=sentry.db.models.fields.foreignkey.FlexibleForeignKey(
34+
on_delete=django.db.models.deletion.CASCADE, to="sentry.organization"
35+
),
36+
),
37+
migrations.AddConstraint(
38+
model_name="dashboardfavoriteuser",
39+
constraint=models.UniqueConstraint(
40+
fields=("user_id", "organization_id", "position"),
41+
name="sentry_dashboardfavoriteuser_user_id_organization_id_position_uniq",
42+
),
43+
),
44+
]

src/sentry/models/dashboard.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class DashboardFavoriteUser(DefaultFieldsModel):
3535
__relocation_scope__ = RelocationScope.Organization
3636

3737
user_id = HybridCloudForeignKey("sentry.User", on_delete="CASCADE")
38-
organization = FlexibleForeignKey("sentry.Organization", null=True)
38+
organization = FlexibleForeignKey("sentry.Organization")
3939
dashboard = FlexibleForeignKey("sentry.Dashboard", on_delete=models.CASCADE)
4040

4141
position = models.PositiveSmallIntegerField(null=True)
@@ -49,6 +49,11 @@ class Meta:
4949
fields=["user_id", "dashboard"],
5050
name="sentry_dashboardfavoriteuser_user_id_dashboard_id_2c7267a5_uniq",
5151
),
52+
# A user can only have one starred dashboard in a specific position
53+
UniqueConstraint(
54+
fields=["user_id", "organization_id", "position"],
55+
name="sentry_dashboardfavoriteuser_user_id_organization_id_position_uniq",
56+
),
5257
]
5358

5459

0 commit comments

Comments
 (0)