summaryrefslogtreecommitdiff
path: root/tests/migrations
diff options
context:
space:
mode:
authorClifford Gama <cliffygamy@gmail.com>2025-07-05 12:47:53 +0200
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2025-07-25 13:59:13 +0200
commit1a7fc0f65d5b2ef56625a8b5897496e28a5834ff (patch)
treef46b1d042f0d375ea0d599572a55092d3a67dbf4 /tests/migrations
parent9ab1991689000821a4d86b8617e1c1455a327482 (diff)
Fixed #36438 -- Made MigrationAutodetector remove generated fields before their base fields.
Thanks to Colton Saska for the report and to Simon Charette for the review.
Diffstat (limited to 'tests/migrations')
-rw-r--r--tests/migrations/test_autodetector.py96
1 files changed, 95 insertions, 1 deletions
diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py
index c5d630293e..c044cc9a99 100644
--- a/tests/migrations/test_autodetector.py
+++ b/tests/migrations/test_autodetector.py
@@ -13,7 +13,7 @@ from django.db.migrations.graph import MigrationGraph
from django.db.migrations.loader import MigrationLoader
from django.db.migrations.questioner import MigrationQuestioner
from django.db.migrations.state import ModelState, ProjectState
-from django.db.models.functions import Concat, Lower
+from django.db.models.functions import Concat, Lower, Upper
from django.test import SimpleTestCase, TestCase, override_settings
from django.test.utils import isolate_lru_cache
@@ -1454,6 +1454,100 @@ class AutodetectorTests(BaseAutodetectorTests):
self.assertOperationTypes(changes, "testapp", 0, ["RemoveField"])
self.assertOperationAttributes(changes, "testapp", 0, 0, name="name")
+ def test_remove_generated_field_before_its_base_field(self):
+ initial_state = [
+ ModelState(
+ "testapp",
+ "Author",
+ [
+ ("name", models.CharField(max_length=20)),
+ (
+ "upper_name",
+ models.GeneratedField(
+ expression=Upper("name"),
+ db_persist=True,
+ output_field=models.CharField(),
+ ),
+ ),
+ ],
+ ),
+ ]
+ updated_state = [ModelState("testapp", "Author", [])]
+ changes = self.get_changes(initial_state, updated_state)
+ self.assertNumberMigrations(changes, "testapp", 1)
+ self.assertOperationTypes(changes, "testapp", 0, ["RemoveField", "RemoveField"])
+ self.assertOperationAttributes(changes, "testapp", 0, 0, name="upper_name")
+ self.assertOperationAttributes(changes, "testapp", 0, 1, name="name")
+
+ def test_remove_generated_field_before_multiple_base_fields(self):
+ initial_state = [
+ ModelState(
+ "testapp",
+ "Author",
+ [
+ ("first_name", models.CharField(max_length=20)),
+ ("last_name", models.CharField(max_length=20)),
+ (
+ "full_name",
+ models.GeneratedField(
+ expression=Concat("first_name", "last_name"),
+ db_persist=True,
+ output_field=models.CharField(),
+ ),
+ ),
+ ],
+ ),
+ ]
+ updated_state = [ModelState("testapp", "Author", [])]
+ changes = self.get_changes(initial_state, updated_state)
+ self.assertNumberMigrations(changes, "testapp", 1)
+ self.assertOperationTypes(
+ changes, "testapp", 0, ["RemoveField", "RemoveField", "RemoveField"]
+ )
+ self.assertOperationAttributes(changes, "testapp", 0, 0, name="full_name")
+ self.assertOperationAttributes(changes, "testapp", 0, 1, name="first_name")
+ self.assertOperationAttributes(changes, "testapp", 0, 2, name="last_name")
+
+ def test_remove_generated_field_and_one_of_multiple_base_fields(self):
+ initial_state = [
+ ModelState(
+ "testapp",
+ "Author",
+ [
+ ("first_name", models.CharField(max_length=20)),
+ ("last_name", models.CharField(max_length=20)),
+ (
+ "full_name",
+ models.GeneratedField(
+ expression=Concat("first_name", "last_name"),
+ db_persist=True,
+ output_field=models.CharField(),
+ ),
+ ),
+ ],
+ ),
+ ]
+ # Only remove full_name and first_name.
+ updated_state = [
+ ModelState(
+ "testapp",
+ "Author",
+ [
+ ("last_name", models.CharField(max_length=20)),
+ ],
+ ),
+ ]
+ changes = self.get_changes(initial_state, updated_state)
+ self.assertNumberMigrations(changes, "testapp", 1)
+ self.assertOperationTypes(
+ changes,
+ "testapp",
+ 0,
+ ["RemoveField", "RemoveField"],
+ )
+ self.assertOperationAttributes(changes, "testapp", 0, 0, name="full_name")
+ self.assertOperationAttributes(changes, "testapp", 0, 1, name="first_name")
+
def test_alter_field(self):
"""Tests autodetection of new fields."""
changes = self.get_changes([self.author_name], [self.author_name_longer])