From 92f0017133c2d31fbd527bab7b08d4d49a582143 Mon Sep 17 00:00:00 2001 From: Akash Kumar Sen Date: Mon, 8 May 2023 23:24:46 +0530 Subject: [PATCH] Refs #34534 -- Reduced Add/RemoveConstraint and Add/RenameIndex operations when optimizing migrations. --- AUTHORS | 1 + django/db/migrations/operations/models.py | 12 ++++++ tests/migrations/test_optimizer.py | 51 +++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/AUTHORS b/AUTHORS index 34f40bbbe6..ea321038ac 100644 --- a/AUTHORS +++ b/AUTHORS @@ -34,6 +34,7 @@ answer newbie questions, and generally made Django that much better: Ahmed Eltawela ajs Akash Agrawal + Akash Kumar Sen Akis Kesoglou Aksel Ethem Akshesh Doshi diff --git a/django/db/migrations/operations/models.py b/django/db/migrations/operations/models.py index 9c5bd5fbcb..b18ef55369 100644 --- a/django/db/migrations/operations/models.py +++ b/django/db/migrations/operations/models.py @@ -929,6 +929,9 @@ class AddIndex(IndexOperation): def reduce(self, operation, app_label): if isinstance(operation, RemoveIndex) and self.index.name == operation.name: return [] + if isinstance(operation, RenameIndex) and self.index.name == operation.old_name: + self.index.name = operation.new_name + return [AddIndex(model_name=self.model_name, index=self.index)] return super().reduce(operation, app_label) @@ -1164,6 +1167,15 @@ class AddConstraint(IndexOperation): def migration_name_fragment(self): return "%s_%s" % (self.model_name_lower, self.constraint.name.lower()) + def reduce(self, operation, app_label): + if ( + isinstance(operation, RemoveConstraint) + and self.model_name_lower == operation.model_name_lower + and self.constraint.name == operation.name + ): + return [] + return super().reduce(operation, app_label) + class RemoveConstraint(IndexOperation): option_name = "constraints" diff --git a/tests/migrations/test_optimizer.py b/tests/migrations/test_optimizer.py index cb4000cb03..ec5f6b4ce9 100644 --- a/tests/migrations/test_optimizer.py +++ b/tests/migrations/test_optimizer.py @@ -2,6 +2,7 @@ from django.db import migrations, models from django.db.migrations import operations from django.db.migrations.optimizer import MigrationOptimizer from django.db.migrations.serializer import serializer_factory +from django.db.models.functions import Abs from django.test import SimpleTestCase from .models import EmptyManager, UnicodeModel @@ -1159,6 +1160,38 @@ class OptimizerTests(SimpleTestCase): ] ) + def test_add_rename_index(self): + tests = [ + models.Index(fields=["weight", "pink"], name="mid_name"), + models.Index(Abs("weight"), name="mid_name"), + models.Index( + Abs("weight"), name="mid_name", condition=models.Q(weight__gt=0) + ), + ] + for index in tests: + with self.subTest(index=index): + renamed_index = index.clone() + renamed_index.name = "new_name" + self.assertOptimizesTo( + [ + migrations.AddIndex("Pony", index), + migrations.RenameIndex( + "Pony", new_name="new_name", old_name="mid_name" + ), + ], + [ + migrations.AddIndex("Pony", renamed_index), + ], + ) + self.assertDoesNotOptimize( + [ + migrations.AddIndex("Pony", index), + migrations.RenameIndex( + "Pony", new_name="new_name", old_name="other_name" + ), + ], + ) + def test_add_remove_index(self): self.assertOptimizesTo( [ @@ -1173,6 +1206,24 @@ class OptimizerTests(SimpleTestCase): [], ) + def test_add_remove_constraint(self): + gt_constraint = models.CheckConstraint( + check=models.Q(pink__gt=2), name="constraint_pony_pink_gt_2" + ) + self.assertOptimizesTo( + [ + migrations.AddConstraint("Pony", gt_constraint), + migrations.RemoveConstraint("Pony", gt_constraint.name), + ], + [], + ) + self.assertDoesNotOptimize( + [ + migrations.AddConstraint("Pony", gt_constraint), + migrations.RemoveConstraint("Pony", "other_name"), + ], + ) + def test_create_model_add_index(self): self.assertOptimizesTo( [