From 19e5cd77f0536b778b00788e34d8199835143855 Mon Sep 17 00:00:00 2001 From: Joel Bohman Date: Fri, 22 Nov 2013 23:31:50 +0100 Subject: [PATCH] Fixed #21497 -- Forced conversion to bytes for very long index names --- AUTHORS | 1 + django/db/backends/schema.py | 3 ++- tests/schema/models.py | 7 +++++++ tests/schema/tests.py | 24 ++++++++++++++++++++++-- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4484c9ba46..93bc04a052 100644 --- a/AUTHORS +++ b/AUTHORS @@ -123,6 +123,7 @@ answer newbie questions, and generally made Django that much better: David Blewett Artem Gnilov Eric Boersma + Joel Bohman Matías Bordese Nate Bragg Sean Brant diff --git a/django/db/backends/schema.py b/django/db/backends/schema.py index 9568400556..96b0c7f697 100644 --- a/django/db/backends/schema.py +++ b/django/db/backends/schema.py @@ -5,6 +5,7 @@ from django.db.backends.creation import BaseDatabaseCreation from django.db.backends.utils import truncate_name from django.db.models.fields.related import ManyToManyField from django.db.transaction import atomic +from django.utils.encoding import force_bytes from django.utils.log import getLogger from django.utils.six.moves import reduce from django.utils.six import callable @@ -703,7 +704,7 @@ class BaseDatabaseSchemaEditor(object): index_name = index_name[1:] # If it's STILL too long, just hash it down if len(index_name) > self.connection.features.max_index_name_length: - index_name = hashlib.md5(index_name).hexdigest()[:self.connection.features.max_index_name_length] + index_name = hashlib.md5(force_bytes(index_name)).hexdigest()[:self.connection.features.max_index_name_length] # It can't start with a number on Oracle, so prepend D if we need to if index_name[0].isdigit(): index_name = "D%s" % index_name[:-1] diff --git a/tests/schema/models.py b/tests/schema/models.py index b79f54699d..06ba8fb760 100644 --- a/tests/schema/models.py +++ b/tests/schema/models.py @@ -95,3 +95,10 @@ class UniqueTest(models.Model): class Meta: app_cache = new_app_cache unique_together = ["year", "slug"] + + +class BookWithLongName(models.Model): + author_foreign_key_with_really_long_field_name = models.ForeignKey(Author) + + class Meta: + app_cache = new_app_cache diff --git a/tests/schema/tests.py b/tests/schema/tests.py index ce6a1128e7..de339132bc 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -7,7 +7,9 @@ from django.db import connection, DatabaseError, IntegrityError from django.db.models.fields import IntegerField, TextField, CharField, SlugField from django.db.models.fields.related import ManyToManyField, ForeignKey from django.db.transaction import atomic -from .models import Author, AuthorWithM2M, Book, BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest +from .models import (Author, AuthorWithM2M, Book, BookWithLongName, + BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, + UniqueTest) class SchemaTests(TransactionTestCase): @@ -21,7 +23,10 @@ class SchemaTests(TransactionTestCase): available_apps = [] - models = [Author, AuthorWithM2M, Book, BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest] + models = [ + Author, AuthorWithM2M, Book, BookWithLongName, BookWithSlug, + BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest, + ] # Utility functions @@ -659,3 +664,18 @@ class SchemaTests(TransactionTestCase): raise SomeError except SomeError: self.assertFalse(connection.in_atomic_block) + + def test_foreign_key_index_long_names_regression(self): + """ + 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(BookWithLongName) + # Ensure the table is there and has the right index + self.assertIn( + "author_foreign_key_with_really_long_field_name_id", + connection.introspection.get_indexes(connection.cursor(), BookWithLongName._meta.db_table), + )