Fixed #23009: Shorten FK identifiers in add_field and make consistent

This commit is contained in:
Andrew Godwin 2014-07-21 10:50:21 +01:00
parent dcb4ed5170
commit 7dacc6ae46
3 changed files with 41 additions and 14 deletions

View File

@ -435,11 +435,7 @@ class BaseDatabaseSchemaEditor(object):
to_column = field.rel.to._meta.get_field(field.rel.field_name).column to_column = field.rel.to._meta.get_field(field.rel.field_name).column
self.deferred_sql.append( self.deferred_sql.append(
self.sql_create_fk % { self.sql_create_fk % {
"name": self.quote_name('%s_refs_%s_%x' % ( "name": self._create_index_name(model, [field.column], suffix="_fk_%s_%s" % (to_table, to_column)),
field.column,
to_column,
abs(hash((model._meta.db_table, to_table)))
)),
"table": self.quote_name(model._meta.db_table), "table": self.quote_name(model._meta.db_table),
"column": self.quote_name(field.column), "column": self.quote_name(field.column),
"to_table": self.quote_name(to_table), "to_table": self.quote_name(to_table),
@ -737,13 +733,15 @@ class BaseDatabaseSchemaEditor(object):
) )
# Does it have a foreign key? # Does it have a foreign key?
if new_field.rel: 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.execute(
self.sql_create_fk % { self.sql_create_fk % {
"table": self.quote_name(model._meta.db_table), "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), "column": self.quote_name(new_field.column),
"to_table": self.quote_name(new_field.rel.to._meta.db_table), "to_table": self.quote_name(to_table),
"to_column": self.quote_name(new_field.rel.get_related_field().column), "to_column": self.quote_name(to_column),
} }
) )
# Rebuild FKs that pointed to us if we previously had to drop them # Rebuild FKs that pointed to us if we previously had to drop them

View File

@ -129,8 +129,16 @@ class UniqueTest(models.Model):
unique_together = ["year", "slug"] 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): 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: class Meta:
apps = new_apps apps = new_apps

View File

@ -9,7 +9,8 @@ from django.db.models.fields.related import ManyToManyField, ForeignKey
from django.db.transaction import atomic from django.db.transaction import atomic
from .models import (Author, AuthorWithM2M, Book, BookWithLongName, from .models import (Author, AuthorWithM2M, Book, BookWithLongName,
BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename,
UniqueTest, Thing, TagThrough, BookWithM2MThrough, AuthorTag, AuthorWithM2MThrough) UniqueTest, Thing, TagThrough, BookWithM2MThrough, AuthorTag, AuthorWithM2MThrough,
AuthorWithEvenLongerName)
class SchemaTests(TransactionTestCase): class SchemaTests(TransactionTestCase):
@ -26,7 +27,7 @@ class SchemaTests(TransactionTestCase):
models = [ models = [
Author, AuthorWithM2M, Book, BookWithLongName, BookWithSlug, Author, AuthorWithM2M, Book, BookWithLongName, BookWithSlug,
BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest,
Thing, TagThrough, BookWithM2MThrough Thing, TagThrough, BookWithM2MThrough, AuthorWithEvenLongerName
] ]
# Utility functions # Utility functions
@ -846,14 +847,15 @@ class SchemaTests(TransactionTestCase):
except SomeError: except SomeError:
self.assertFalse(connection.in_atomic_block) 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): def test_foreign_key_index_long_names_regression(self):
""" """
Regression test for #21497. Only affects databases that supports Regression test for #21497.
foreign keys. Only affects databases that supports foreign keys.
""" """
# Create the table # Create the table
with connection.schema_editor() as editor: with connection.schema_editor() as editor:
editor.create_model(Author) editor.create_model(AuthorWithEvenLongerName)
editor.create_model(BookWithLongName) editor.create_model(BookWithLongName)
# Find the properly shortened column name # Find the properly shortened column name
column_name = connection.ops.quote_name("author_foreign_key_with_really_long_field_name_id") 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), 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): def test_creation_deletion_reserved_names(self):
""" """
Tries creating a model's table, and then deleting it when it has a Tries creating a model's table, and then deleting it when it has a