From 7dacc6ae4657ecc18bd92a94b50950871f914168 Mon Sep 17 00:00:00 2001 From: Andrew Godwin Date: Mon, 21 Jul 2014 10:50:21 +0100 Subject: [PATCH] Fixed #23009: Shorten FK identifiers in add_field and make consistent --- django/db/backends/schema.py | 14 ++++++-------- tests/schema/models.py | 10 +++++++++- tests/schema/tests.py | 31 ++++++++++++++++++++++++++----- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/django/db/backends/schema.py b/django/db/backends/schema.py index a82524b2a0..9645c40761 100644 --- a/django/db/backends/schema.py +++ b/django/db/backends/schema.py @@ -435,11 +435,7 @@ class BaseDatabaseSchemaEditor(object): to_column = field.rel.to._meta.get_field(field.rel.field_name).column self.deferred_sql.append( self.sql_create_fk % { - "name": self.quote_name('%s_refs_%s_%x' % ( - field.column, - to_column, - abs(hash((model._meta.db_table, to_table))) - )), + "name": self._create_index_name(model, [field.column], suffix="_fk_%s_%s" % (to_table, to_column)), "table": self.quote_name(model._meta.db_table), "column": self.quote_name(field.column), "to_table": self.quote_name(to_table), @@ -737,13 +733,15 @@ class BaseDatabaseSchemaEditor(object): ) # Does it have a foreign key? if new_field.rel: + to_table = new_field.rel.to._meta.db_table + to_column = new_field.rel.get_related_field().column self.execute( self.sql_create_fk % { "table": self.quote_name(model._meta.db_table), - "name": self._create_index_name(model, [new_field.column], suffix="_fk"), + "name": self._create_index_name(model, [new_field.column], suffix="_fk_%s_%s" % (to_table, to_column)), "column": self.quote_name(new_field.column), - "to_table": self.quote_name(new_field.rel.to._meta.db_table), - "to_column": self.quote_name(new_field.rel.get_related_field().column), + "to_table": self.quote_name(to_table), + "to_column": self.quote_name(to_column), } ) # Rebuild FKs that pointed to us if we previously had to drop them diff --git a/tests/schema/models.py b/tests/schema/models.py index f5f59f7416..c3d6593c99 100644 --- a/tests/schema/models.py +++ b/tests/schema/models.py @@ -129,8 +129,16 @@ class UniqueTest(models.Model): unique_together = ["year", "slug"] +class AuthorWithEvenLongerName(models.Model): + name = models.CharField(max_length=255) + height = models.PositiveIntegerField(null=True, blank=True) + + class Meta: + apps = new_apps + + class BookWithLongName(models.Model): - author_foreign_key_with_really_long_field_name = models.ForeignKey(Author) + author_foreign_key_with_really_long_field_name = models.ForeignKey(AuthorWithEvenLongerName) class Meta: apps = new_apps diff --git a/tests/schema/tests.py b/tests/schema/tests.py index 1acf132445..0bbf4302c9 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -9,7 +9,8 @@ from django.db.models.fields.related import ManyToManyField, ForeignKey from django.db.transaction import atomic from .models import (Author, AuthorWithM2M, Book, BookWithLongName, BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, - UniqueTest, Thing, TagThrough, BookWithM2MThrough, AuthorTag, AuthorWithM2MThrough) + UniqueTest, Thing, TagThrough, BookWithM2MThrough, AuthorTag, AuthorWithM2MThrough, + AuthorWithEvenLongerName) class SchemaTests(TransactionTestCase): @@ -26,7 +27,7 @@ class SchemaTests(TransactionTestCase): models = [ Author, AuthorWithM2M, Book, BookWithLongName, BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest, - Thing, TagThrough, BookWithM2MThrough + Thing, TagThrough, BookWithM2MThrough, AuthorWithEvenLongerName ] # Utility functions @@ -846,14 +847,15 @@ class SchemaTests(TransactionTestCase): except SomeError: self.assertFalse(connection.in_atomic_block) + @unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support") def test_foreign_key_index_long_names_regression(self): """ - Regression test for #21497. Only affects databases that supports - foreign keys. + Regression test for #21497. + Only affects databases that supports foreign keys. """ # Create the table with connection.schema_editor() as editor: - editor.create_model(Author) + editor.create_model(AuthorWithEvenLongerName) editor.create_model(BookWithLongName) # Find the properly shortened column name column_name = connection.ops.quote_name("author_foreign_key_with_really_long_field_name_id") @@ -864,6 +866,25 @@ class SchemaTests(TransactionTestCase): self.get_indexes(BookWithLongName._meta.db_table), ) + @unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support") + def test_add_foreign_key_long_names(self): + """ + Regression test for #23009. + Only affects databases that supports foreign keys. + """ + # Create the initial tables + with connection.schema_editor() as editor: + editor.create_model(AuthorWithEvenLongerName) + editor.create_model(BookWithLongName) + # Add a second FK, this would fail due to long ref name before the fix + new_field = ForeignKey(AuthorWithEvenLongerName, related_name="something") + new_field.set_attributes_from_name("author_other_really_long_named_i_mean_so_long_fk") + with connection.schema_editor() as editor: + editor.add_field( + BookWithLongName, + new_field, + ) + def test_creation_deletion_reserved_names(self): """ Tries creating a model's table, and then deleting it when it has a