diff --git a/django/db/backends/postgresql/schema.py b/django/db/backends/postgresql/schema.py index d512ecefb6..68c5bf31af 100644 --- a/django/db/backends/postgresql/schema.py +++ b/django/db/backends/postgresql/schema.py @@ -130,6 +130,13 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): return using_sql return "" + def _get_sequence_name(self, table, column): + with self.connection.cursor() as cursor: + for sequence in self.connection.introspection.get_sequences(cursor, table): + if sequence["column"] == column: + return sequence["name"] + return None + def _alter_column_type_sql(self, model, old_field, new_field, new_type): # Drop indexes on varchar/text/citext columns that are changing to a # different type. @@ -193,44 +200,48 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): } ) column = strip_quotes(new_field.column) - sequence_name = "%s_%s_seq" % (table, column) fragment, _ = super()._alter_column_type_sql( model, old_field, new_field, new_type ) - return fragment, [ - ( - # Drop the sequence if exists (Django 4.1+ identity columns - # don't have it). - self.sql_delete_sequence - % { - "sequence": self.quote_name(sequence_name), - }, - [], - ), - ] + # Drop the sequence if exists (Django 4.1+ identity columns don't + # have it). + other_actions = [] + if sequence_name := self._get_sequence_name(table, column): + other_actions = [ + ( + self.sql_delete_sequence + % { + "sequence": self.quote_name(sequence_name), + }, + [], + ) + ] + return fragment, other_actions elif new_is_auto and old_is_auto and old_internal_type != new_internal_type: fragment, _ = super()._alter_column_type_sql( model, old_field, new_field, new_type ) column = strip_quotes(new_field.column) - sequence_name = f"{table}_{column}_seq" db_types = { "AutoField": "integer", "BigAutoField": "bigint", "SmallAutoField": "smallint", } - return fragment, [ - # Alter the sequence type if exists (Django 4.1+ identity - # columns don't have it). - ( - self.sql_alter_sequence_type - % { - "sequence": self.quote_name(sequence_name), - "type": db_types[new_internal_type], - }, - [], - ), - ] + # Alter the sequence type if exists (Django 4.1+ identity columns + # don't have it). + other_actions = [] + if sequence_name := self._get_sequence_name(table, column): + other_actions = [ + ( + self.sql_alter_sequence_type + % { + "sequence": self.quote_name(sequence_name), + "type": db_types[new_internal_type], + }, + [], + ), + ] + return fragment, other_actions else: return super()._alter_column_type_sql(model, old_field, new_field, new_type) diff --git a/tests/schema/tests.py b/tests/schema/tests.py index 32dde9aaed..a2b72cd42a 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -1896,14 +1896,30 @@ class SchemaTests(TransactionTestCase): new_field.set_attributes_from_name("id") with connection.schema_editor() as editor: editor.alter_field(SerialAutoField, old_field, new_field, strict=True) + sequence_name = f"{table}_{column}_seq" with connection.cursor() as cursor: cursor.execute( "SELECT data_type FROM pg_sequences WHERE sequencename = %s", - [f"{table}_{column}_seq"], + [sequence_name], ) row = cursor.fetchone() sequence_data_type = row[0] if row and row[0] else None self.assertEqual(sequence_data_type, "bigint") + # Rename the column. + old_field = new_field + new_field = AutoField(primary_key=True) + new_field.model = SerialAutoField + new_field.set_attributes_from_name("renamed_id") + with connection.schema_editor() as editor: + editor.alter_field(SerialAutoField, old_field, new_field, strict=True) + with connection.cursor() as cursor: + cursor.execute( + "SELECT data_type FROM pg_sequences WHERE sequencename = %s", + [sequence_name], + ) + row = cursor.fetchone() + sequence_data_type = row[0] if row and row[0] else None + self.assertEqual(sequence_data_type, "integer") finally: with connection.cursor() as cursor: cursor.execute(f'DROP TABLE "{table}"')