Fixed #23100: Individual FK creation missing dependencies

This commit is contained in:
Andrew Godwin 2014-07-28 10:32:43 -07:00
parent 668d432d0a
commit cb60d22bd9
2 changed files with 39 additions and 3 deletions

View File

@ -699,7 +699,7 @@ class MigrationAutodetector(object):
old_model_name = self.renamed_models.get((app_label, model_name), model_name) old_model_name = self.renamed_models.get((app_label, model_name), model_name)
old_model_state = self.from_state.models[app_label, old_model_name] old_model_state = self.from_state.models[app_label, old_model_name]
new_model_state = self.to_state.models[app_label, model_name] new_model_state = self.to_state.models[app_label, model_name]
field = new_model_state.get_field_by_name(field_name) field = self.new_apps.get_model(app_label, model_name)._meta.get_field_by_name(field_name)[0]
# Scan to see if this is actually a rename! # Scan to see if this is actually a rename!
field_dec = self.deep_deconstruct(field) field_dec = self.deep_deconstruct(field)
found_rename = False found_rename = False
@ -727,6 +727,25 @@ class MigrationAutodetector(object):
break break
if found_rename: if found_rename:
continue continue
# Fields that are foreignkeys/m2ms depend on stuff
dependencies = []
if field.rel and field.rel.to:
# Account for FKs to swappable models
swappable_setting = getattr(field, 'swappable_setting', None)
if swappable_setting is not None:
dep_app_label = "__setting__"
dep_object_name = swappable_setting
else:
dep_app_label = field.rel.to._meta.app_label
dep_object_name = field.rel.to._meta.object_name
dependencies = [(dep_app_label, dep_object_name, None, True)]
if getattr(field.rel, "through", None) and not field.rel.through._meta.auto_created:
dependencies.append((
field.rel.through._meta.app_label,
field.rel.through._meta.object_name,
None,
True
))
# 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() and not isinstance(field, models.ManyToManyField): if not field.null and not field.has_default() and not isinstance(field, models.ManyToManyField):
field = field.clone() field = field.clone()
@ -738,7 +757,8 @@ class MigrationAutodetector(object):
name=field_name, name=field_name,
field=field, field=field,
preserve_default=False, preserve_default=False,
) ),
dependencies=dependencies,
) )
else: else:
self.add_operation( self.add_operation(
@ -747,7 +767,8 @@ class MigrationAutodetector(object):
model_name=model_name, model_name=model_name,
name=field_name, name=field_name,
field=field, field=field,
) ),
dependencies=dependencies,
) )
def generate_removed_fields(self): def generate_removed_fields(self):

View File

@ -1105,3 +1105,18 @@ class AutodetectorTests(TestCase):
self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Aardvark") self.assertOperationAttributes(changes, 'testapp', 0, 0, name="Aardvark")
self.assertOperationAttributes(changes, 'testapp', 0, 1, name="author") self.assertOperationAttributes(changes, 'testapp', 0, 1, name="author")
self.assertOperationAttributes(changes, 'testapp', 0, 2, name="Author") self.assertOperationAttributes(changes, 'testapp', 0, 2, name="Author")
def test_fk_dependency_other_app(self):
"""
Tests that ForeignKeys correctly depend on other apps' models (#23100)
"""
# Make state
before = self.make_project_state([self.author_name, self.book])
after = self.make_project_state([self.author_with_book, self.book])
autodetector = MigrationAutodetector(before, after)
changes = autodetector._detect_changes()
# Right number of migrations?
self.assertNumberMigrations(changes, 'testapp', 1)
self.assertOperationTypes(changes, 'testapp', 0, ["AddField"])
self.assertOperationAttributes(changes, 'testapp', 0, 0, name="book")
self.assertEqual(changes['testapp'][0].dependencies, [("otherapp", "__first__")])