summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNan Liu <45443761+nanlliu@users.noreply.github.com>2020-05-24 08:59:46 +0800
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-05-26 08:34:14 +0200
commit114da2d0455594bae0bbda8f2b1d46c5ec854956 (patch)
tree1c93443ae4feb00a7cea559227b1cee569df48c1
parentccf3cecbaf7cdaeeb027ca37bd93efb35ff7393b (diff)
[3.1.x] Fixed #31416 -- Made autodetector find dependencies for MTI model creation on base fields removal.
Removing a base field must take place before adding a new inherited model that has a field with the same name. Backport of 33c365781abbcc1b21a31b31d95d344a174df0d5 from master
-rw-r--r--django/db/migrations/autodetector.py10
-rw-r--r--tests/migrations/test_autodetector.py25
2 files changed, 35 insertions, 0 deletions
diff --git a/django/db/migrations/autodetector.py b/django/db/migrations/autodetector.py
index 30616c0172..85c3013897 100644
--- a/django/db/migrations/autodetector.py
+++ b/django/db/migrations/autodetector.py
@@ -563,6 +563,16 @@ class MigrationAutodetector:
if isinstance(base, str) and "." in base:
base_app_label, base_name = base.split(".", 1)
dependencies.append((base_app_label, base_name, None, True))
+ # Depend on the removal of base fields if the new model has
+ # a field with the same name.
+ old_base_model_state = self.from_state.models.get((base_app_label, base_name))
+ new_base_model_state = self.to_state.models.get((base_app_label, base_name))
+ if old_base_model_state and new_base_model_state:
+ removed_base_fields = set(old_base_model_state.fields).difference(
+ new_base_model_state.fields,
+ ).intersection(model_state.fields)
+ for removed_base_field in removed_base_fields:
+ dependencies.append((base_app_label, base_name, removed_base_field, False))
# Depend on the other end of the primary key if it's a relation
if primary_key_rel:
dependencies.append((
diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py
index daff57fc2c..10af72561b 100644
--- a/tests/migrations/test_autodetector.py
+++ b/tests/migrations/test_autodetector.py
@@ -2454,3 +2454,28 @@ class AutodetectorTests(TestCase):
self.assertNumberMigrations(changes, 'app', 1)
self.assertOperationTypes(changes, 'app', 0, ['DeleteModel'])
self.assertOperationAttributes(changes, 'app', 0, 0, name='Dog')
+
+ def test_add_model_with_field_removed_from_base_model(self):
+ """
+ Removing a base field takes place before adding a new inherited model
+ that has a field with the same name.
+ """
+ before = [
+ ModelState('app', 'readable', [
+ ('id', models.AutoField(primary_key=True)),
+ ('title', models.CharField(max_length=200)),
+ ]),
+ ]
+ after = [
+ ModelState('app', 'readable', [
+ ('id', models.AutoField(primary_key=True)),
+ ]),
+ ModelState('app', 'book', [
+ ('title', models.CharField(max_length=200)),
+ ], bases=('app.readable',)),
+ ]
+ changes = self.get_changes(before, after)
+ self.assertNumberMigrations(changes, 'app', 1)
+ self.assertOperationTypes(changes, 'app', 0, ['RemoveField', 'CreateModel'])
+ self.assertOperationAttributes(changes, 'app', 0, 0, name='title', model_name='readable')
+ self.assertOperationAttributes(changes, 'app', 0, 1, name='book')