[1.8.x] Fixed #24435 -- Prevented m2m field removal and addition in migrations when changing blank

Thanks Mark Tranchant for the report and Tim Graham for the test and
review.

Backport of a9e29fae10 from master
This commit is contained in:
Markus Holtermann 2015-03-04 09:36:53 +01:00
parent 44dd65fb2c
commit bff446c205
2 changed files with 25 additions and 2 deletions

View File

@ -848,8 +848,16 @@ class MigrationAutodetector(object):
old_field_dec = self.deep_deconstruct(old_field)
new_field_dec = self.deep_deconstruct(new_field)
if old_field_dec != new_field_dec:
if (not isinstance(old_field, models.ManyToManyField) and
not isinstance(new_field, models.ManyToManyField)):
both_m2m = (
isinstance(old_field, models.ManyToManyField) and
isinstance(new_field, models.ManyToManyField)
)
neither_m2m = (
not isinstance(old_field, models.ManyToManyField) and
not isinstance(new_field, models.ManyToManyField)
)
if both_m2m or neither_m2m:
# Either both fields are m2m or neither is
preserve_default = True
if (old_field.null and not new_field.null and not new_field.has_default() and
not isinstance(new_field, models.ManyToManyField)):
@ -870,6 +878,7 @@ class MigrationAutodetector(object):
)
)
else:
# We cannot alter between m2m and concrete fields
self._generate_removed_field(app_label, model_name, field_name)
self._generate_added_field(app_label, model_name, field_name)

View File

@ -127,6 +127,10 @@ class AutodetectorTests(TestCase):
("id", models.AutoField(primary_key=True)),
("publishers", models.ManyToManyField("testapp.Publisher")),
])
author_with_m2m_blank = ModelState("testapp", "Author", [
("id", models.AutoField(primary_key=True)),
("publishers", models.ManyToManyField("testapp.Publisher", blank=True)),
])
author_with_m2m_through = ModelState("testapp", "Author", [
("id", models.AutoField(primary_key=True)),
("publishers", models.ManyToManyField("testapp.Publisher", through="testapp.Contract")),
@ -1263,6 +1267,16 @@ class AutodetectorTests(TestCase):
self.assertOperationTypes(changes, 'testapp', 0, ["AddField"])
self.assertOperationAttributes(changes, 'testapp', 0, 0, name="publishers")
def test_alter_many_to_many(self):
before = self.make_project_state([self.author_with_m2m, self.publisher])
after = self.make_project_state([self.author_with_m2m_blank, self.publisher])
autodetector = MigrationAutodetector(before, after)
changes = autodetector._detect_changes()
# Right number/type of migrations?
self.assertNumberMigrations(changes, 'testapp', 1)
self.assertOperationTypes(changes, 'testapp', 0, ["AlterField"])
self.assertOperationAttributes(changes, 'testapp', 0, 0, name="publishers")
def test_create_with_through_model(self):
"""
Adding a m2m with a through model and the models that use it should be