summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAndrés Reverón Molina <andressser@gmail.com>2024-12-16 13:54:51 +0100
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2024-12-17 09:59:39 +0100
commitb44efdfe543c9b9f12690b59777e6b275cb08103 (patch)
tree0188cfc1d3173fc95492a415695a083ff732fb32 /tests
parent44281bc2123dac1b127000c84c759f9678021826 (diff)
Fixed #34856 -- Fixed references to index_together in historical migrations.
While AlterUniqueTogether has been documented to be still allowed in historical migrations for the foreseeable future it has been crashing since 2abf417c815c20 was merged because the latter removed support for Meta.index_together which the migration framework uses to render models to perform schema changes. CreateModel(options["unique_together"]) was also affected. Refs #27236. Co-authored-by: Simon Charette <charette.s@gmail.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/migrations/test_operations.py205
1 files changed, 205 insertions, 0 deletions
diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py
index 6312a7d4a2..33a7b6dc3d 100644
--- a/tests/migrations/test_operations.py
+++ b/tests/migrations/test_operations.py
@@ -3329,6 +3329,52 @@ class OperationTests(OperationTestBase):
self.assertColumnExists("test_rnflut_pony", "pink")
self.assertColumnNotExists("test_rnflut_pony", "blue")
+ def test_rename_field_index_together(self):
+ app_label = "test_rnflit"
+ operations = [
+ migrations.CreateModel(
+ "Pony",
+ fields=[
+ ("id", models.AutoField(primary_key=True)),
+ ("pink", models.IntegerField(default=3)),
+ ("weight", models.FloatField()),
+ ],
+ options={
+ "index_together": [("weight", "pink")],
+ },
+ ),
+ ]
+ project_state = self.apply_operations(app_label, ProjectState(), operations)
+
+ operation = migrations.RenameField("Pony", "pink", "blue")
+ new_state = project_state.clone()
+ operation.state_forwards("test_rnflit", new_state)
+ self.assertIn("blue", new_state.models["test_rnflit", "pony"].fields)
+ self.assertNotIn("pink", new_state.models["test_rnflit", "pony"].fields)
+ # index_together has the renamed column.
+ self.assertIn(
+ "blue", new_state.models["test_rnflit", "pony"].options["index_together"][0]
+ )
+ self.assertNotIn(
+ "pink", new_state.models["test_rnflit", "pony"].options["index_together"][0]
+ )
+
+ # Rename field.
+ self.assertColumnExists("test_rnflit_pony", "pink")
+ self.assertColumnNotExists("test_rnflit_pony", "blue")
+ with connection.schema_editor() as editor:
+ operation.database_forwards("test_rnflit", editor, project_state, new_state)
+ self.assertColumnExists("test_rnflit_pony", "blue")
+ self.assertColumnNotExists("test_rnflit_pony", "pink")
+ # The index constraint has been ported over.
+ self.assertIndexExists("test_rnflit_pony", ["weight", "blue"])
+ # Reversal.
+ with connection.schema_editor() as editor:
+ operation.database_backwards(
+ "test_rnflit", editor, new_state, project_state
+ )
+ self.assertIndexExists("test_rnflit_pony", ["weight", "pink"])
+
def test_rename_field_with_db_column(self):
project_state = self.apply_operations(
"test_rfwdbc",
@@ -3822,6 +3868,63 @@ class OperationTests(OperationTestBase):
with self.assertRaisesMessage(ValueError, msg):
migrations.RenameIndex("Pony", new_name="new_idx_name")
+ def test_rename_index_unnamed_index(self):
+ app_label = "test_rninui"
+ operations = [
+ migrations.CreateModel(
+ "Pony",
+ fields=[
+ ("id", models.AutoField(primary_key=True)),
+ ("pink", models.IntegerField(default=3)),
+ ("weight", models.FloatField()),
+ ],
+ options={
+ "index_together": [("weight", "pink")],
+ },
+ ),
+ ]
+ project_state = self.apply_operations(app_label, ProjectState(), operations)
+ table_name = app_label + "_pony"
+ self.assertIndexNameNotExists(table_name, "new_pony_test_idx")
+ operation = migrations.RenameIndex(
+ "Pony", new_name="new_pony_test_idx", old_fields=("weight", "pink")
+ )
+ self.assertEqual(
+ operation.describe(),
+ "Rename unnamed index for ('weight', 'pink') on Pony to new_pony_test_idx",
+ )
+ self.assertEqual(
+ operation.migration_name_fragment,
+ "rename_pony_weight_pink_new_pony_test_idx",
+ )
+ new_state = project_state.clone()
+ operation.state_forwards(app_label, new_state)
+ # Rename index.
+ with connection.schema_editor() as editor:
+ operation.database_forwards(app_label, editor, project_state, new_state)
+ self.assertIndexNameExists(table_name, "new_pony_test_idx")
+ # Reverse is a no-op.
+ with connection.schema_editor() as editor, self.assertNumQueries(0):
+ operation.database_backwards(app_label, editor, new_state, project_state)
+ self.assertIndexNameExists(table_name, "new_pony_test_idx")
+ # Reapply, RenameIndex operation is a noop when the old and new name
+ # match.
+ with connection.schema_editor() as editor:
+ operation.database_forwards(app_label, editor, new_state, project_state)
+ self.assertIndexNameExists(table_name, "new_pony_test_idx")
+ # Deconstruction.
+ definition = operation.deconstruct()
+ self.assertEqual(definition[0], "RenameIndex")
+ self.assertEqual(definition[1], [])
+ self.assertEqual(
+ definition[2],
+ {
+ "model_name": "Pony",
+ "new_name": "new_pony_test_idx",
+ "old_fields": ("weight", "pink"),
+ },
+ )
+
def test_rename_index_unknown_unnamed_index(self):
app_label = "test_rninuui"
project_state = self.set_up_test_model(app_label)
@@ -3892,6 +3995,33 @@ class OperationTests(OperationTestBase):
self.assertIsNot(old_model, new_model)
self.assertEqual(new_model._meta.indexes[0].name, "new_pony_pink_idx")
+ def test_rename_index_state_forwards_unnamed_index(self):
+ app_label = "test_rnidsfui"
+ operations = [
+ migrations.CreateModel(
+ "Pony",
+ fields=[
+ ("id", models.AutoField(primary_key=True)),
+ ("pink", models.IntegerField(default=3)),
+ ("weight", models.FloatField()),
+ ],
+ options={
+ "index_together": [("weight", "pink")],
+ },
+ ),
+ ]
+ project_state = self.apply_operations(app_label, ProjectState(), operations)
+ old_model = project_state.apps.get_model(app_label, "Pony")
+ new_state = project_state.clone()
+
+ operation = migrations.RenameIndex(
+ "Pony", new_name="new_pony_pink_idx", old_fields=("weight", "pink")
+ )
+ operation.state_forwards(app_label, new_state)
+ new_model = new_state.apps.get_model(app_label, "Pony")
+ self.assertIsNot(old_model, new_model)
+ self.assertEqual(new_model._meta.indexes[0].name, "new_pony_pink_idx")
+
@skipUnlessDBFeature("supports_expression_indexes")
def test_add_func_index(self):
app_label = "test_addfuncin"
@@ -4011,6 +4141,58 @@ class OperationTests(OperationTestBase):
# Ensure the index is still there
self.assertIndexExists("test_alflin_pony", ["pink"])
+ def test_alter_index_together(self):
+ """
+ Tests the AlterIndexTogether operation.
+ """
+ project_state = self.set_up_test_model("test_alinto")
+ # Test the state alteration
+ operation = migrations.AlterIndexTogether("Pony", [("pink", "weight")])
+ self.assertEqual(
+ operation.describe(), "Alter index_together for Pony (1 constraint(s))"
+ )
+ self.assertEqual(
+ operation.migration_name_fragment,
+ "alter_pony_index_together",
+ )
+ new_state = project_state.clone()
+ operation.state_forwards("test_alinto", new_state)
+ self.assertEqual(
+ len(
+ project_state.models["test_alinto", "pony"].options.get(
+ "index_together", set()
+ )
+ ),
+ 0,
+ )
+ self.assertEqual(
+ len(
+ new_state.models["test_alinto", "pony"].options.get(
+ "index_together", set()
+ )
+ ),
+ 1,
+ )
+ # Make sure there's no matching index
+ self.assertIndexNotExists("test_alinto_pony", ["pink", "weight"])
+ # Test the database alteration
+ with connection.schema_editor() as editor:
+ operation.database_forwards("test_alinto", editor, project_state, new_state)
+ self.assertIndexExists("test_alinto_pony", ["pink", "weight"])
+ # And test reversal
+ with connection.schema_editor() as editor:
+ operation.database_backwards(
+ "test_alinto", editor, new_state, project_state
+ )
+ self.assertIndexNotExists("test_alinto_pony", ["pink", "weight"])
+ # And deconstruction
+ definition = operation.deconstruct()
+ self.assertEqual(definition[0], "AlterIndexTogether")
+ self.assertEqual(definition[1], [])
+ self.assertEqual(
+ definition[2], {"name": "Pony", "index_together": {("pink", "weight")}}
+ )
+
def test_alter_index_together_remove(self):
operation = migrations.AlterIndexTogether("Pony", None)
self.assertEqual(
@@ -4021,6 +4203,29 @@ class OperationTests(OperationTestBase):
"~ Alter index_together for Pony (0 constraint(s))",
)
+ @skipUnlessDBFeature("allows_multiple_constraints_on_same_fields")
+ def test_alter_index_together_remove_with_unique_together(self):
+ app_label = "test_alintoremove_wunto"
+ table_name = "%s_pony" % app_label
+ project_state = self.set_up_test_model(app_label, unique_together=True)
+ self.assertUniqueConstraintExists(table_name, ["pink", "weight"])
+ # Add index together.
+ new_state = project_state.clone()
+ operation = migrations.AlterIndexTogether("Pony", [("pink", "weight")])
+ operation.state_forwards(app_label, new_state)
+ with connection.schema_editor() as editor:
+ operation.database_forwards(app_label, editor, project_state, new_state)
+ self.assertIndexExists(table_name, ["pink", "weight"])
+ # Remove index together.
+ project_state = new_state
+ new_state = project_state.clone()
+ operation = migrations.AlterIndexTogether("Pony", set())
+ operation.state_forwards(app_label, new_state)
+ with connection.schema_editor() as editor:
+ operation.database_forwards(app_label, editor, project_state, new_state)
+ self.assertIndexNotExists(table_name, ["pink", "weight"])
+ self.assertUniqueConstraintExists(table_name, ["pink", "weight"])
+
def test_add_constraint(self):
project_state = self.set_up_test_model("test_addconstraint")
gt_check = models.Q(pink__gt=2)