Fixed #31335 -- Fixed removing composed composed Meta constraints/indexes on foreign keys on MySQL.
This commit is contained in:
parent
1b08e9bf7d
commit
b731e88415
|
@ -1,5 +1,6 @@
|
|||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
from django.db.models import NOT_PROVIDED
|
||||
from django.db.models import NOT_PROVIDED, F, UniqueConstraint
|
||||
from django.db.models.constants import LOOKUP_SEP
|
||||
|
||||
|
||||
class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
||||
|
@ -117,6 +118,23 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
|||
[effective_default],
|
||||
)
|
||||
|
||||
def remove_constraint(self, model, constraint):
|
||||
if isinstance(constraint, UniqueConstraint):
|
||||
self._create_missing_fk_index(
|
||||
model,
|
||||
fields=constraint.fields,
|
||||
expressions=constraint.expressions,
|
||||
)
|
||||
super().remove_constraint(model, constraint)
|
||||
|
||||
def remove_index(self, model, index):
|
||||
self._create_missing_fk_index(
|
||||
model,
|
||||
fields=[field_name for field_name, _ in index.fields_orders],
|
||||
expressions=index.expressions,
|
||||
)
|
||||
super().remove_index(model, index)
|
||||
|
||||
def _field_should_be_indexed(self, model, field):
|
||||
if not super()._field_should_be_indexed(model, field):
|
||||
return False
|
||||
|
@ -140,6 +158,7 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
|||
model,
|
||||
*,
|
||||
fields,
|
||||
expressions=None,
|
||||
):
|
||||
"""
|
||||
MySQL can remove an implicit FK index on a field when that field is
|
||||
|
@ -150,14 +169,36 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
|||
Manually create an implicit FK index to make it possible to remove the
|
||||
composed index.
|
||||
"""
|
||||
first_field = model._meta.get_field(fields[0])
|
||||
first_field_name = None
|
||||
if fields:
|
||||
first_field_name = fields[0]
|
||||
elif (
|
||||
expressions
|
||||
and self.connection.features.supports_expression_indexes
|
||||
and isinstance(expressions[0], F)
|
||||
and LOOKUP_SEP not in expressions[0].name
|
||||
):
|
||||
first_field_name = expressions[0].name
|
||||
|
||||
if not first_field_name:
|
||||
return
|
||||
|
||||
first_field = model._meta.get_field(first_field_name)
|
||||
if first_field.get_internal_type() == "ForeignKey":
|
||||
constraint_names = self._constraint_names(
|
||||
model,
|
||||
[first_field.column],
|
||||
index=True,
|
||||
column = self.connection.introspection.identifier_converter(
|
||||
first_field.column
|
||||
)
|
||||
if not constraint_names:
|
||||
with self.connection.cursor() as cursor:
|
||||
constraint_names = [
|
||||
name
|
||||
for name, infodict in self.connection.introspection.get_constraints(
|
||||
cursor, model._meta.db_table
|
||||
).items()
|
||||
if infodict["index"] and infodict["columns"][0] == column
|
||||
]
|
||||
# There are no other indexes that starts with the FK field, only
|
||||
# the index that is expected to be deleted.
|
||||
if len(constraint_names) == 1:
|
||||
self.execute(
|
||||
self._create_index_sql(model, fields=[first_field], suffix="")
|
||||
)
|
||||
|
|
|
@ -2735,6 +2735,24 @@ class SchemaTests(TransactionTestCase):
|
|||
editor.remove_index(Book, index)
|
||||
self.assertNotIn(index.name, self.get_constraints(table))
|
||||
|
||||
def test_composed_index_with_fk(self):
|
||||
index = Index(fields=["author", "title"], name="book_author_title_idx")
|
||||
self._test_composed_index_with_fk(index)
|
||||
|
||||
def test_composed_desc_index_with_fk(self):
|
||||
index = Index(fields=["-author", "title"], name="book_author_title_idx")
|
||||
self._test_composed_index_with_fk(index)
|
||||
|
||||
@skipUnlessDBFeature("supports_expression_indexes")
|
||||
def test_composed_func_index_with_fk(self):
|
||||
index = Index(F("author"), F("title"), name="book_author_title_idx")
|
||||
self._test_composed_index_with_fk(index)
|
||||
|
||||
@skipUnlessDBFeature("supports_expression_indexes")
|
||||
def test_composed_desc_func_index_with_fk(self):
|
||||
index = Index(F("author").desc(), F("title"), name="book_author_title_idx")
|
||||
self._test_composed_index_with_fk(index)
|
||||
|
||||
@skipUnlessDBFeature("supports_expression_indexes")
|
||||
def test_composed_func_transform_index_with_fk(self):
|
||||
index = Index(F("title__lower"), name="book_title_lower_idx")
|
||||
|
@ -2756,6 +2774,13 @@ class SchemaTests(TransactionTestCase):
|
|||
editor.remove_constraint(Book, constraint)
|
||||
self.assertNotIn(constraint.name, self.get_constraints(table))
|
||||
|
||||
def test_composed_constraint_with_fk(self):
|
||||
constraint = UniqueConstraint(
|
||||
fields=["author", "title"],
|
||||
name="book_author_title_uniq",
|
||||
)
|
||||
self._test_composed_constraint_with_fk(constraint)
|
||||
|
||||
@skipUnlessDBFeature(
|
||||
"supports_column_check_constraints", "can_introspect_check_constraints"
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue