Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,7 @@ answer newbie questions, and generally made Django that much better:
Yann Fouillat <gagaro42@gmail.com>
Yann Malet
Yash Jhunjhunwala
Yassin Bahri <https://github.com/yassinbahri>
Yasushi Masuda <whosaysni@gmail.com>
ye7cakf02@sneakemail.com
ymasuda@ethercube.com
Expand Down
2 changes: 2 additions & 0 deletions django/db/backends/base/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,8 @@ class BaseDatabaseFeatures:
supports_comments = False
# Does the backend support column comments in ADD COLUMN statements?
supports_comments_inline = False
# Does the backend support changing column comments without altering type?
supports_independent_comment_alteration = False

# Does the backend support stored generated columns?
supports_stored_generated_columns = False
Expand Down
15 changes: 14 additions & 1 deletion django/db/backends/base/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,9 @@ def _alter_field(
and (not new_field.db_index or new_field.unique)
):
# Find the index for this field
meta_constraint_names = {
constraint.name for constraint in model._meta.constraints
}
meta_index_names = {index.name for index in model._meta.indexes}
# Retrieve only BTREE indexes since this is what's created with
# db_index=True.
Expand All @@ -1092,7 +1095,7 @@ def _alter_field(
[old_field.column],
index=True,
type_=Index.suffix,
exclude=meta_index_names,
exclude=meta_constraint_names | meta_index_names,
)
for index_name in index_names:
# The only way to check if an index was created with
Expand Down Expand Up @@ -1151,13 +1154,23 @@ def _alter_field(
or (
self.connection.features.supports_comments
and old_field.db_comment != new_field.db_comment
and not self.connection.features.supports_independent_comment_alteration
)
):
fragment, other_actions = self._alter_column_type_sql(
model, old_field, new_field, new_type, old_collation, new_collation
)
actions.append(fragment)
post_actions.extend(other_actions)
elif (
self.connection.features.supports_comments
and old_field.db_comment != new_field.db_comment
and self.connection.features.supports_independent_comment_alteration
):
sql, params = self._alter_column_comment_sql(
model, new_field, new_type, new_field.db_comment
)
post_actions.append((sql, params))

if new_field.has_db_default():
if (
Expand Down
2 changes: 1 addition & 1 deletion django/db/backends/mysql/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def _rename_field_sql(self, table, old_field, new_field, new_type):
return super()._rename_field_sql(table, old_field, new_field, new_type)

def _alter_column_comment_sql(self, model, new_field, new_type, new_db_comment):
# Comment is alter when altering the column type.
# Comment is altered when altering the column type.
return "", []

def _comment_sql(self, comment):
Expand Down
1 change: 1 addition & 0 deletions django/db/backends/oracle/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_deferrable_unique_constraints = True
truncates_names = True
supports_comments = True
supports_independent_comment_alteration = True
supports_tablespaces = True
supports_sequence_reset = False
can_introspect_materialized_views = True
Expand Down
1 change: 1 addition & 0 deletions django/db/backends/postgresql/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
has_select_for_no_key_update = True
can_release_savepoints = True
supports_comments = True
supports_independent_comment_alteration = True
supports_tablespaces = True
supports_transactions = True
can_introspect_materialized_views = True
Expand Down
82 changes: 80 additions & 2 deletions tests/schema/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,41 @@ class Meta:
"generated", self.get_indexes(GeneratedFieldIndexedModel._meta.db_table)
)

@isolate_apps("schema")
@skipUnlessDBFeature(
"supports_stored_generated_columns",
"supports_independent_comment_alteration",
)
def test_alter_generated_field_base_field_comment(self):
class GenFieldModelComment(Model):
name = CharField(max_length=100)
name_lower = GeneratedField(
expression=Lower("name"), db_persist=True, output_field=CharField()
)

class Meta:
app_label = "schema"

with connection.schema_editor() as editor:
editor.create_model(GenFieldModelComment)

old_field = GenFieldModelComment._meta.get_field("name")
new_field = CharField(max_length=100, db_comment="Super useful comment")
new_field.set_attributes_from_name("name")
new_field.model = GenFieldModelComment
with (
connection.schema_editor() as editor,
CaptureQueriesContext(connection) as ctx,
):
editor.alter_field(GenFieldModelComment, old_field, new_field, strict=True)

self.assertEqual(len(ctx), 1)
self.assertIn("COMMENT ON COLUMN", ctx.captured_queries[0]["sql"])
self.assertEqual(
self.get_column_comment(GenFieldModelComment._meta.db_table, "name"),
"Super useful comment",
)

@isolate_apps("schema")
def test_add_auto_field(self):
class AddAutoFieldModel(Model):
Expand Down Expand Up @@ -4113,6 +4148,42 @@ def test_remove_db_index_doesnt_remove_custom_indexes(self):
finally:
AuthorWithIndexedName._meta.indexes = []

@skipUnlessDBFeature("allows_multiple_constraints_on_same_fields")
def test_remove_db_index_doesnt_remove_unique_constraints(self):
with connection.schema_editor() as editor:
editor.create_model(AuthorCharFieldWithIndex)
constraint = UniqueConstraint(
fields=["char_field"], name="author_char_field_uniq"
)
try:
AuthorCharFieldWithIndex._meta.constraints = [constraint]
with connection.schema_editor() as editor:
editor.add_constraint(AuthorCharFieldWithIndex, constraint)
db_index_name = editor._create_index_name(
table_name=AuthorCharFieldWithIndex._meta.db_table,
column_names=("char_field",),
)
old_constraints = self.get_constraints(
AuthorCharFieldWithIndex._meta.db_table
)
self.assertIn(constraint.name, old_constraints)
self.assertIn(db_index_name, old_constraints)

old_field = AuthorCharFieldWithIndex._meta.get_field("char_field")
new_field = CharField(max_length=31)
new_field.set_attributes_from_name("char_field")
with connection.schema_editor() as editor:
editor.alter_field(
AuthorCharFieldWithIndex, old_field, new_field, strict=True
)
new_constraints = self.get_constraints(
AuthorCharFieldWithIndex._meta.db_table
)
self.assertNotIn(db_index_name, new_constraints)
self.assertIn(constraint.name, new_constraints)
finally:
AuthorCharFieldWithIndex._meta.constraints = []

def test_order_index(self):
"""
Indexes defined with ordering (ASC/DESC) defined on column
Expand Down Expand Up @@ -5103,12 +5174,19 @@ def test_add_db_comment_and_default_charfield(self):
def test_alter_db_comment(self):
with connection.schema_editor() as editor:
editor.create_model(Author)
# Add comment.
old_field = Author._meta.get_field("name")
new_field = CharField(max_length=255, db_comment="Custom comment")
new_field.set_attributes_from_name("name")
with connection.schema_editor() as editor:
with (
connection.schema_editor() as editor,
CaptureQueriesContext(connection) as ctx,
):
editor.alter_field(Author, old_field, new_field, strict=True)
self.assertEqual(len(ctx), 1)
if connection.features.supports_independent_comment_alteration:
self.assertIn("COMMENT ON COLUMN", ctx.captured_queries[0]["sql"])
else:
self.assertIn("ALTER TABLE", ctx.captured_queries[0]["sql"])
self.assertEqual(
self.get_column_comment(Author._meta.db_table, "name"),
"Custom comment",
Expand Down
Loading