Skip to content

Commit a7a6ea7

Browse files
authored
Merge pull request #337 from cmu-delphi/development
Anotehr round of migrations
2 parents 20bf305 + dbbf7a3 commit a7a6ea7

2 files changed

Lines changed: 83 additions & 129 deletions

File tree

Lines changed: 83 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,93 @@
1-
# Generated by Django 5.2.5 on 2026-06-16 22:01
1+
# Generated by Django 5.2.5 on 2026-06-16 20:35
22

3-
import django.db.models.deletion
4-
from django.db import migrations, models
3+
from django.db import migrations
54

6-
from indicatorsets.odp_migration import ensure_original_data_provider_schema
75

6+
INDICATOR_SET_TABLE = "indicatorsets_indicatorset"
7+
PROVIDER_TABLE = "indicatorsets_originaldataprovider"
8+
CHAR_COLUMN = "original_data_provider"
9+
FK_COLUMN = "original_data_provider_id"
810

9-
def drop_orphan_original_data_provider_table(apps, schema_editor):
10-
"""Clean up partial/failed deploys before CreateModel runs."""
11-
with schema_editor.connection.cursor() as cursor:
12-
cursor.execute("SET FOREIGN_KEY_CHECKS=0")
11+
12+
def _get_indicator_set_columns(cursor):
13+
cursor.execute(
14+
"""
15+
SELECT COLUMN_NAME, DATA_TYPE
16+
FROM information_schema.COLUMNS
17+
WHERE TABLE_SCHEMA = DATABASE()
18+
AND TABLE_NAME = %s
19+
""",
20+
[INDICATOR_SET_TABLE],
21+
)
22+
return {row[0]: row[1] for row in cursor.fetchall()}
23+
24+
25+
def _table_exists(cursor, table_name):
26+
cursor.execute("SHOW TABLES LIKE %s", [table_name])
27+
return cursor.fetchone() is not None
28+
29+
30+
def _drop_foreign_keys(cursor):
31+
cursor.execute(
32+
"""
33+
SELECT CONSTRAINT_NAME
34+
FROM information_schema.KEY_COLUMN_USAGE
35+
WHERE TABLE_SCHEMA = DATABASE()
36+
AND TABLE_NAME = %s
37+
AND COLUMN_NAME = %s
38+
AND REFERENCED_TABLE_NAME IS NOT NULL
39+
""",
40+
[INDICATOR_SET_TABLE, FK_COLUMN],
41+
)
42+
for (constraint_name,) in cursor.fetchall():
1343
cursor.execute(
14-
"""
15-
SELECT CONSTRAINT_NAME
16-
FROM information_schema.KEY_COLUMN_USAGE
17-
WHERE TABLE_SCHEMA = DATABASE()
18-
AND TABLE_NAME = 'indicatorsets_indicatorset'
19-
AND COLUMN_NAME = 'original_data_provider_id'
20-
AND REFERENCED_TABLE_NAME IS NOT NULL
21-
"""
44+
f"ALTER TABLE `{INDICATOR_SET_TABLE}` DROP FOREIGN KEY `{constraint_name}`"
2245
)
23-
for (constraint_name,) in cursor.fetchall():
46+
47+
48+
def revert_original_data_provider_schema(apps, schema_editor):
49+
"""
50+
Ensure DB matches CharField original_data_provider with no ODP lookup table.
51+
52+
Handles fresh DBs, orphan ODP tables from failed deploys, and FK-based schemas.
53+
"""
54+
with schema_editor.connection.cursor() as cursor:
55+
if not _table_exists(cursor, INDICATOR_SET_TABLE):
56+
return
57+
58+
columns = _get_indicator_set_columns(cursor)
59+
has_char = CHAR_COLUMN in columns
60+
has_fk = FK_COLUMN in columns
61+
has_provider_table = _table_exists(cursor, PROVIDER_TABLE)
62+
63+
cursor.execute("SET FOREIGN_KEY_CHECKS=0")
64+
65+
if has_fk:
66+
if has_provider_table:
67+
if not has_char:
68+
cursor.execute(
69+
f"ALTER TABLE `{INDICATOR_SET_TABLE}` "
70+
f"ADD COLUMN `{CHAR_COLUMN}` varchar(255) NOT NULL DEFAULT ''"
71+
)
72+
has_char = True
73+
74+
cursor.execute(
75+
f"""
76+
UPDATE `{INDICATOR_SET_TABLE}` iset
77+
LEFT JOIN `{PROVIDER_TABLE}` odp
78+
ON iset.`{FK_COLUMN}` = odp.`id`
79+
SET iset.`{CHAR_COLUMN}` = COALESCE(odp.`name`, '')
80+
"""
81+
)
82+
83+
_drop_foreign_keys(cursor)
2484
cursor.execute(
25-
f"ALTER TABLE `indicatorsets_indicatorset` "
26-
f"DROP FOREIGN KEY `{constraint_name}`"
85+
f"ALTER TABLE `{INDICATOR_SET_TABLE}` DROP COLUMN `{FK_COLUMN}`"
2786
)
28-
cursor.execute("DROP TABLE IF EXISTS `indicatorsets_originaldataprovider`")
87+
88+
if has_provider_table:
89+
cursor.execute(f"DROP TABLE IF EXISTS `{PROVIDER_TABLE}`")
90+
2991
cursor.execute("SET FOREIGN_KEY_CHECKS=1")
3092

3193

@@ -37,60 +99,7 @@ class Migration(migrations.Migration):
3799

38100
operations = [
39101
migrations.RunPython(
40-
drop_orphan_original_data_provider_table,
102+
revert_original_data_provider_schema,
41103
migrations.RunPython.noop,
42104
),
43-
migrations.CreateModel(
44-
name="OriginalDataProvider",
45-
fields=[
46-
(
47-
"id",
48-
models.BigAutoField(
49-
auto_created=True,
50-
primary_key=True,
51-
serialize=False,
52-
verbose_name="ID",
53-
),
54-
),
55-
(
56-
"name",
57-
models.CharField(max_length=255, unique=True, verbose_name="Name"),
58-
),
59-
(
60-
"group",
61-
models.CharField(
62-
choices=[
63-
("us_government", "U.S. Government"),
64-
("us_states", "U.S. States"),
65-
("individual", "Individual providers"),
66-
],
67-
"constraints": [
68-
models.UniqueConstraint(
69-
fields=("name", "group"),
70-
name="unique_data_provider_name_group",
71-
)
72-
],
73-
},
74-
),
75-
migrations.AlterField(
76-
model_name="indicatorset",
77-
name="original_data_provider",
78-
field=models.ForeignKey(
79-
blank=True,
80-
help_text="Original data provider of the Indicator Set",
81-
null=True,
82-
on_delete=django.db.models.deletion.SET_NULL,
83-
related_name="indicator_sets",
84-
to="indicatorsets.originaldataprovider",
85-
verbose_name="Original Data Provider",
86-
),
87-
),
88-
],
89-
database_operations=[
90-
migrations.RunPython(
91-
ensure_original_data_provider_schema,
92-
migrations.RunPython.noop,
93-
),
94-
],
95-
),
96105
]

src/indicatorsets/migrations/0011_alter_indicatorset_original_data_provider_and_more.py

Lines changed: 0 additions & 55 deletions
This file was deleted.

0 commit comments

Comments
 (0)