[1.7.x] Fixed #22435 -- Prevented adding a ManyToManyField from prompting for a default.
Thanks andrewsg for the report.
Backport of 3818d96426
from master
This commit is contained in:
parent
61fd00d4fd
commit
f8fa735dc2
|
@ -1,6 +1,7 @@
|
||||||
import re
|
import re
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
from django.db.migrations import operations
|
from django.db.migrations import operations
|
||||||
from django.db.migrations.migration import Migration
|
from django.db.migrations.migration import Migration
|
||||||
from django.db.migrations.questioner import MigrationQuestioner
|
from django.db.migrations.questioner import MigrationQuestioner
|
||||||
|
@ -299,7 +300,7 @@ class MigrationAutodetector(object):
|
||||||
if found_rename:
|
if found_rename:
|
||||||
continue
|
continue
|
||||||
# You can't just add NOT NULL fields with no default
|
# You can't just add NOT NULL fields with no default
|
||||||
if not field.null and not field.has_default():
|
if not field.null and not field.has_default() and not isinstance(field, models.ManyToManyField):
|
||||||
field = field.clone()
|
field = field.clone()
|
||||||
field.default = self.questioner.ask_not_null_addition(field_name, model_name)
|
field.default = self.questioner.ask_not_null_addition(field_name, model_name)
|
||||||
self.add_to_migration(
|
self.add_to_migration(
|
||||||
|
|
|
@ -37,6 +37,10 @@ class AutodetectorTests(TestCase):
|
||||||
author_proxy_notproxy = ModelState("testapp", "AuthorProxy", [], {}, ("testapp.author", ))
|
author_proxy_notproxy = ModelState("testapp", "AuthorProxy", [], {}, ("testapp.author", ))
|
||||||
author_unmanaged = ModelState("testapp", "AuthorUnmanaged", [], {"managed": False}, ("testapp.author", ))
|
author_unmanaged = ModelState("testapp", "AuthorUnmanaged", [], {"managed": False}, ("testapp.author", ))
|
||||||
author_unmanaged_managed = ModelState("testapp", "AuthorUnmanaged", [], {}, ("testapp.author", ))
|
author_unmanaged_managed = ModelState("testapp", "AuthorUnmanaged", [], {}, ("testapp.author", ))
|
||||||
|
author_with_m2m = ModelState("testapp", "Author", [
|
||||||
|
("id", models.AutoField(primary_key=True)),
|
||||||
|
("publishers", models.ManyToManyField("testapp.Publisher")),
|
||||||
|
])
|
||||||
publisher = ModelState("testapp", "Publisher", [("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=100))])
|
publisher = ModelState("testapp", "Publisher", [("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=100))])
|
||||||
publisher_with_author = ModelState("testapp", "Publisher", [("id", models.AutoField(primary_key=True)), ("author", models.ForeignKey("testapp.Author")), ("name", models.CharField(max_length=100))])
|
publisher_with_author = ModelState("testapp", "Publisher", [("id", models.AutoField(primary_key=True)), ("author", models.ForeignKey("testapp.Author")), ("name", models.CharField(max_length=100))])
|
||||||
publisher_with_book = ModelState("testapp", "Publisher", [("id", models.AutoField(primary_key=True)), ("author", models.ForeignKey("otherapp.Book")), ("name", models.CharField(max_length=100))])
|
publisher_with_book = ModelState("testapp", "Publisher", [("id", models.AutoField(primary_key=True)), ("author", models.ForeignKey("otherapp.Book")), ("name", models.CharField(max_length=100))])
|
||||||
|
@ -619,6 +623,28 @@ class AutodetectorTests(TestCase):
|
||||||
self.assertEqual(action.__class__.__name__, "DeleteModel")
|
self.assertEqual(action.__class__.__name__, "DeleteModel")
|
||||||
self.assertEqual(action.name, "Publisher")
|
self.assertEqual(action.name, "Publisher")
|
||||||
|
|
||||||
|
def test_add_many_to_many(self):
|
||||||
|
"""
|
||||||
|
Adding a ManyToManyField should not prompt for a default (#22435).
|
||||||
|
"""
|
||||||
|
class CustomQuestioner(MigrationQuestioner):
|
||||||
|
def ask_not_null_addition(self, field_name, model_name):
|
||||||
|
raise Exception("Should not have prompted for not null addition")
|
||||||
|
|
||||||
|
before = self.make_project_state([self.author_empty, self.publisher])
|
||||||
|
# Add ManyToManyField to author model
|
||||||
|
after = self.make_project_state([self.author_with_m2m, self.publisher])
|
||||||
|
autodetector = MigrationAutodetector(before, after, CustomQuestioner())
|
||||||
|
changes = autodetector._detect_changes()
|
||||||
|
# Right number of migrations?
|
||||||
|
self.assertEqual(len(changes['testapp']), 1)
|
||||||
|
migration = changes['testapp'][0]
|
||||||
|
# Right actions in right order?
|
||||||
|
self.assertEqual(len(migration.operations), 1)
|
||||||
|
action = migration.operations[0]
|
||||||
|
self.assertEqual(action.__class__.__name__, "AddField")
|
||||||
|
self.assertEqual(action.name, "publishers")
|
||||||
|
|
||||||
def test_many_to_many_removed_before_through_model(self):
|
def test_many_to_many_removed_before_through_model(self):
|
||||||
"""
|
"""
|
||||||
Removing a ManyToManyField and the "through" model in the same change must remove
|
Removing a ManyToManyField and the "through" model in the same change must remove
|
||||||
|
|
Loading…
Reference in New Issue