1
0
mirror of https://github.com/django/django.git synced 2025-04-18 06:14:37 +00:00

Fixed -- Made migrations add FK constraints for existing columns

When altering from e.g. an IntegerField to a ForeignKey, Django didn't
add a constraint.

Backport of f4f0060feaee6bbd76a0d575487682bc541111e4 from master
This commit is contained in:
Jean-Louis Fuchs 2015-03-05 13:41:15 +01:00 committed by Markus Holtermann
parent 7f2d60996c
commit 283b630d63
4 changed files with 49 additions and 5 deletions
django/db/backends
docs/releases
tests/schema

@ -675,9 +675,9 @@ class BaseDatabaseSchemaEditor(object):
}
)
# Does it have a foreign key?
if new_field.rel and \
(fks_dropped or (old_field.rel and not old_field.db_constraint)) and \
new_field.db_constraint:
if (new_field.rel and
(fks_dropped or not old_field.rel or not old_field.db_constraint) and
new_field.db_constraint):
self.execute(self._create_fk_sql(model, new_field, "_fk_%(to_table)s_%(to_column)s"))
# Rebuild FKs that pointed to us if we previously had to drop them
if old_field.primary_key and new_field.primary_key and old_type != new_type:

@ -11,3 +11,6 @@ Bugfixes
* Fixed crash when coercing ``ManyRelatedManager`` to a string
(:ticket:`24352`).
* Fixed a bug that prevented migrations from adding a FK constraint
for an existing column. (:ticket:`24447`).

@ -87,6 +87,15 @@ class BookWithM2M(models.Model):
apps = new_apps
class BookWithoutFK(models.Model):
author = models.IntegerField()
title = models.CharField(max_length=100, db_index=True)
pub_date = models.DateTimeField()
class Meta:
apps = new_apps
class TagThrough(models.Model):
book = models.ForeignKey("schema.BookWithM2MThrough")
tag = models.ForeignKey("schema.TagM2MTest")

@ -11,7 +11,7 @@ from .fields import CustomManyToManyField, InheritedManyToManyField
from .models import (Author, AuthorWithDefaultHeight, AuthorWithM2M, Book, BookWithLongName,
BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename,
UniqueTest, Thing, TagThrough, BookWithM2MThrough, AuthorTag, AuthorWithM2MThrough,
AuthorWithEvenLongerName, BookWeak, Note, BookWithO2O)
AuthorWithEvenLongerName, BookWeak, Note, BookWithO2O, BookWithoutFK)
class SchemaTests(TransactionTestCase):
@ -29,7 +29,7 @@ class SchemaTests(TransactionTestCase):
Author, AuthorWithM2M, Book, BookWithLongName, BookWithSlug,
BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest,
Thing, TagThrough, BookWithM2MThrough, AuthorWithEvenLongerName,
BookWeak, BookWithO2O,
BookWeak, BookWithO2O, BookWithoutFK,
]
# Utility functions
@ -536,6 +536,38 @@ class SchemaTests(TransactionTestCase):
else:
self.fail("No FK constraint for author_id found")
@unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support")
def test_alter_to_fk(self):
"""
#24447 - Tests adding a FK constraint for an existing column
"""
# Create the tables
with connection.schema_editor() as editor:
editor.create_model(Author)
editor.create_model(BookWithoutFK)
# Ensure no FK constraint exists
constraints = self.get_constraints(BookWithoutFK._meta.db_table)
for name, details in constraints.items():
if details['foreign_key']:
self.fail('Found an unexpected FK constraint to %s' % details['columns'])
new_field = ForeignKey(Author)
new_field.set_attributes_from_name("author")
with connection.schema_editor() as editor:
editor.alter_field(
BookWithoutFK,
BookWithoutFK._meta.get_field_by_name("author")[0],
new_field,
strict=True,
)
constraints = self.get_constraints(BookWithoutFK._meta.db_table)
# Ensure FK constraint exists
for name, details in constraints.items():
if details['foreign_key'] and details['columns'] == ["author_id"]:
self.assertEqual(details['foreign_key'], ('schema_author', 'id'))
break
else:
self.fail("No FK constraint for author_id found")
@unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support")
def test_alter_o2o_to_fk(self):
"""