Skip to content

Commit 211d2bf

Browse files
LilyAcorntimgraham
authored andcommitted
[1.11.x] Fixed #28043 -- Prevented AddIndex and RemoveIndex from mutating model state.
Backport of 63afe3a from master
1 parent ccb3b0e commit 211d2bf

File tree

4 files changed

+34
-1
lines changed

4 files changed

+34
-1
lines changed

django/db/migrations/operations/models.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,10 @@ def __init__(self, model_name, index):
777777

778778
def state_forwards(self, app_label, state):
779779
model_state = state.models[app_label, self.model_name_lower]
780-
model_state.options[self.option_name].append(self.index)
780+
indexes = list(model_state.options[self.option_name])
781+
indexes.append(self.index.clone())
782+
model_state.options[self.option_name] = indexes
783+
state.reload_model(app_label, self.model_name_lower, delay=True)
781784

782785
def database_forwards(self, app_label, schema_editor, from_state, to_state):
783786
model = to_state.apps.get_model(app_label, self.model_name)
@@ -821,6 +824,7 @@ def state_forwards(self, app_label, state):
821824
model_state = state.models[app_label, self.model_name_lower]
822825
indexes = model_state.options[self.option_name]
823826
model_state.options[self.option_name] = [idx for idx in indexes if idx.name != self.name]
827+
state.reload_model(app_label, self.model_name_lower, delay=True)
824828

825829
def database_forwards(self, app_label, schema_editor, from_state, to_state):
826830
model = from_state.apps.get_model(app_label, self.model_name)

django/db/migrations/state.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,9 @@ def clone(self):
584584
app_label=self.app_label,
585585
name=self.name,
586586
fields=list(self.fields),
587+
# Since options are shallow-copied here, operations such as
588+
# AddIndex must replace their option (e.g 'indexes') rather
589+
# than mutating it.
587590
options=dict(self.options),
588591
bases=self.bases,
589592
managers=list(self.managers),

docs/releases/1.11.1.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,6 @@ Bugfixes
6969

7070
* Fixed crash in ``BaseGeometryWidget.get_context()`` when overriding existing
7171
``attrs`` (:ticket:`28105`).
72+
73+
* Prevented ``AddIndex`` and ``RemoveIndex`` from mutating model state
74+
(:ticket:`28043`).

tests/migrations/test_operations.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,6 +1491,29 @@ def test_remove_index(self):
14911491
self.unapply_operations("test_rmin", project_state, operations=operations)
14921492
self.assertIndexExists("test_rmin_pony", ["pink", "weight"])
14931493

1494+
def test_add_index_state_forwards(self):
1495+
project_state = self.set_up_test_model('test_adinsf')
1496+
index = models.Index(fields=['pink'], name='test_adinsf_pony_pink_idx')
1497+
old_model = project_state.apps.get_model('test_adinsf', 'Pony')
1498+
new_state = project_state.clone()
1499+
1500+
operation = migrations.AddIndex('Pony', index)
1501+
operation.state_forwards('test_adinsf', new_state)
1502+
new_model = new_state.apps.get_model('test_adinsf', 'Pony')
1503+
self.assertIsNot(old_model, new_model)
1504+
1505+
def test_remove_index_state_forwards(self):
1506+
project_state = self.set_up_test_model('test_rminsf')
1507+
index = models.Index(fields=['pink'], name='test_rminsf_pony_pink_idx')
1508+
migrations.AddIndex('Pony', index).state_forwards('test_rminsf', project_state)
1509+
old_model = project_state.apps.get_model('test_rminsf', 'Pony')
1510+
new_state = project_state.clone()
1511+
1512+
operation = migrations.RemoveIndex('Pony', 'test_rminsf_pony_pink_idx')
1513+
operation.state_forwards('test_rminsf', new_state)
1514+
new_model = new_state.apps.get_model('test_rminsf', 'Pony')
1515+
self.assertIsNot(old_model, new_model)
1516+
14941517
def test_alter_field_with_index(self):
14951518
"""
14961519
Test AlterField operation with an index to ensure indexes created via

0 commit comments

Comments
 (0)