summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Cail <bcail@crossway.org>2024-01-31 15:25:30 -0500
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2024-02-09 07:02:52 +0100
commit8b7ddd1b621e1396cf87c08faf11937732f09dcd (patch)
treecbe5af298be4a66724ded25a325fa8aebe4aed70
parent9c5e382b981608a26f2c55f1259d9e823fee5f15 (diff)
Refs #34534 -- Reduced constraint operations with Meta.constraints when optimizing migrations.
-rw-r--r--django/db/migrations/operations/models.py34
-rw-r--r--tests/migrations/test_autodetector.py27
-rw-r--r--tests/migrations/test_optimizer.py63
3 files changed, 115 insertions, 9 deletions
diff --git a/django/db/migrations/operations/models.py b/django/db/migrations/operations/models.py
index 38c68f3ff3..34b14107a7 100644
--- a/django/db/migrations/operations/models.py
+++ b/django/db/migrations/operations/models.py
@@ -342,6 +342,40 @@ class CreateModel(ModelOperation):
managers=self.managers,
),
]
+ elif isinstance(operation, AddConstraint):
+ return [
+ CreateModel(
+ self.name,
+ fields=self.fields,
+ options={
+ **self.options,
+ "constraints": [
+ *self.options.get("constraints", []),
+ operation.constraint,
+ ],
+ },
+ bases=self.bases,
+ managers=self.managers,
+ ),
+ ]
+ elif isinstance(operation, RemoveConstraint):
+ options_constraints = [
+ constraint
+ for constraint in self.options.get("constraints", [])
+ if constraint.name != operation.name
+ ]
+ return [
+ CreateModel(
+ self.name,
+ fields=self.fields,
+ options={
+ **self.options,
+ "constraints": options_constraints,
+ },
+ bases=self.bases,
+ managers=self.managers,
+ ),
+ ]
return super().reduce(operation, app_label)
diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py
index 340805b259..d36b72907d 100644
--- a/tests/migrations/test_autodetector.py
+++ b/tests/migrations/test_autodetector.py
@@ -2762,21 +2762,23 @@ class AutodetectorTests(BaseAutodetectorTests):
},
)
changes = self.get_changes([], [author])
- added_constraint = models.CheckConstraint(
+ constraint = models.CheckConstraint(
check=models.Q(name__contains="Bob"), name="name_contains_bob"
)
# Right number of migrations?
self.assertEqual(len(changes["otherapp"]), 1)
# Right number of actions?
migration = changes["otherapp"][0]
- self.assertEqual(len(migration.operations), 2)
+ self.assertEqual(len(migration.operations), 1)
# Right actions order?
- self.assertOperationTypes(
- changes, "otherapp", 0, ["CreateModel", "AddConstraint"]
- )
- self.assertOperationAttributes(changes, "otherapp", 0, 0, name="Author")
+ self.assertOperationTypes(changes, "otherapp", 0, ["CreateModel"])
self.assertOperationAttributes(
- changes, "otherapp", 0, 1, model_name="author", constraint=added_constraint
+ changes,
+ "otherapp",
+ 0,
+ 0,
+ name="Author",
+ options={"constraints": [constraint]},
)
def test_add_constraints(self):
@@ -4177,7 +4179,7 @@ class AutodetectorTests(BaseAutodetectorTests):
changes,
"testapp",
0,
- ["CreateModel", "AddConstraint"],
+ ["CreateModel"],
)
self.assertOperationAttributes(
changes,
@@ -4185,7 +4187,14 @@ class AutodetectorTests(BaseAutodetectorTests):
0,
0,
name="Author",
- options={"order_with_respect_to": "book"},
+ options={
+ "order_with_respect_to": "book",
+ "constraints": [
+ models.CheckConstraint(
+ check=models.Q(_order__gt=1), name="book_order_gt_1"
+ )
+ ],
+ },
)
def test_add_model_order_with_respect_to_index(self):
diff --git a/tests/migrations/test_optimizer.py b/tests/migrations/test_optimizer.py
index ece6580ad8..5c1fe3020e 100644
--- a/tests/migrations/test_optimizer.py
+++ b/tests/migrations/test_optimizer.py
@@ -1326,3 +1326,66 @@ class OptimizerTests(SimpleTestCase):
),
],
)
+
+ def test_create_model_add_constraint(self):
+ gt_constraint = models.CheckConstraint(
+ check=models.Q(weight__gt=0), name="pony_weight_gt_0"
+ )
+ self.assertOptimizesTo(
+ [
+ migrations.CreateModel(
+ name="Pony",
+ fields=[
+ ("weight", models.IntegerField()),
+ ],
+ ),
+ migrations.AddConstraint("Pony", gt_constraint),
+ ],
+ [
+ migrations.CreateModel(
+ name="Pony",
+ fields=[
+ ("weight", models.IntegerField()),
+ ],
+ options={"constraints": [gt_constraint]},
+ ),
+ ],
+ )
+
+ def test_create_model_remove_constraint(self):
+ self.assertOptimizesTo(
+ [
+ migrations.CreateModel(
+ name="Pony",
+ fields=[
+ ("weight", models.IntegerField()),
+ ],
+ options={
+ "constraints": [
+ models.CheckConstraint(
+ check=models.Q(weight__gt=0), name="pony_weight_gt_0"
+ ),
+ models.UniqueConstraint(
+ "weight", name="pony_weight_unique"
+ ),
+ ],
+ },
+ ),
+ migrations.RemoveConstraint("Pony", "pony_weight_gt_0"),
+ ],
+ [
+ migrations.CreateModel(
+ name="Pony",
+ fields=[
+ ("weight", models.IntegerField()),
+ ],
+ options={
+ "constraints": [
+ models.UniqueConstraint(
+ "weight", name="pony_weight_unique"
+ ),
+ ]
+ },
+ ),
+ ],
+ )