diff --git a/django/db/backends/schema.py b/django/db/backends/schema.py index 0671efbb1f..fadb34eac7 100644 --- a/django/db/backends/schema.py +++ b/django/db/backends/schema.py @@ -635,7 +635,7 @@ class BaseDatabaseSchemaEditor(object): self.execute( self.sql_create_pk % { "table": self.quote_name(model._meta.db_table), - "name": self._create_index_name(model, [new_field.column], suffix="_pk"), + "name": self.quote_name(self._create_index_name(model, [new_field.column], suffix="_pk")), "columns": self.quote_name(new_field.column), } ) @@ -668,7 +668,7 @@ class BaseDatabaseSchemaEditor(object): self.execute( self.sql_create_check % { "table": self.quote_name(model._meta.db_table), - "name": self._create_index_name(model, [new_field.column], suffix="_check"), + "name": self.quote_name(self._create_index_name(model, [new_field.column], suffix="_check")), "column": self.quote_name(new_field.column), "check": new_db_params['check'], } @@ -761,7 +761,7 @@ class BaseDatabaseSchemaEditor(object): columns = [field.column for field in fields] return self.sql_create_index % { "table": self.quote_name(model._meta.db_table), - "name": self._create_index_name(model, columns, suffix=suffix), + "name": self.quote_name(self._create_index_name(model, columns, suffix=suffix)), "columns": ", ".join(self.quote_name(column) for column in columns), "extra": "", } @@ -778,7 +778,7 @@ class BaseDatabaseSchemaEditor(object): return self.sql_create_fk % { "table": self.quote_name(from_table), - "name": self._create_index_name(model, [from_column], suffix=suffix), + "name": self.quote_name(self._create_index_name(model, [from_column], suffix=suffix)), "column": self.quote_name(from_column), "to_table": self.quote_name(to_table), "to_column": self.quote_name(to_column), @@ -787,14 +787,14 @@ class BaseDatabaseSchemaEditor(object): def _create_unique_sql(self, model, columns): return self.sql_create_unique % { "table": self.quote_name(model._meta.db_table), - "name": self._create_index_name(model, columns, suffix="_uniq"), + "name": self.quote_name(self._create_index_name(model, columns, suffix="_uniq")), "columns": ", ".join(self.quote_name(column) for column in columns), } def _delete_constraint_sql(self, template, model, name): return template % { "table": self.quote_name(model._meta.db_table), - "name": name, + "name": self.quote_name(name), } def _constraint_names(self, model, column_names=None, unique=None, diff --git a/docs/releases/1.7.1.txt b/docs/releases/1.7.1.txt index 0a75f22e4b..ff8228103d 100644 --- a/docs/releases/1.7.1.txt +++ b/docs/releases/1.7.1.txt @@ -55,3 +55,6 @@ Bugfixes * Formats for Welsh (``cy``) and several Chinese locales (``zh_CN``, ``zh_Hans``, ``zh_Hant`` and ``zh_TW``) have been added. Formats for Macedonian have been fixed (trailing dot removed, :ticket:`23532`). + +* Added quoting of constraint names in the SQL generated by migrations to + prevent crash with uppercase characters in the name (:ticket:`23065`). diff --git a/tests/schema/tests.py b/tests/schema/tests.py index c51ef97106..02207ff6e9 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -1040,3 +1040,53 @@ class SchemaTests(TransactionTestCase): DatabaseError, lambda: list(Thing.objects.all()), ) + + @unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support") + def test_remove_constraints_capital_letters(self): + """ + #23065 - Constraint names must be quoted if they contain capital letters. + """ + def get_field(*args, **kwargs): + kwargs['db_column'] = "CamelCase" + field = kwargs.pop('field_class', IntegerField)(*args, **kwargs) + field.set_attributes_from_name("CamelCase") + return field + + model = Author + field = get_field() + table = model._meta.db_table + column = field.column + + with connection.schema_editor() as editor: + editor.create_model(model) + editor.add_field(model, field) + + editor.execute( + editor.sql_create_index % { + "table": editor.quote_name(table), + "name": editor.quote_name("CamelCaseIndex"), + "columns": editor.quote_name(column), + "extra": "", + } + ) + editor.alter_field(model, get_field(db_index=True), field) + + editor.execute( + editor.sql_create_unique % { + "table": editor.quote_name(table), + "name": editor.quote_name("CamelCaseUniqConstraint"), + "columns": editor.quote_name(field.column), + } + ) + editor.alter_field(model, get_field(unique=True), field) + + editor.execute( + editor.sql_create_fk % { + "table": editor.quote_name(table), + "name": editor.quote_name("CamelCaseFKConstraint"), + "column": editor.quote_name(column), + "to_table": editor.quote_name(table), + "to_column": editor.quote_name(model._meta.auto_field.column), + } + ) + editor.alter_field(model, get_field(Author, field_class=ForeignKey), field)