Skip to content

Commit 8520d2c

Browse files
committed
add index creation/deletion support to SchemaEditor.alter_field()
1 parent 0c9e3d1 commit 8520d2c

File tree

2 files changed

+49
-4
lines changed

2 files changed

+49
-4
lines changed

django_mongodb/features.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
8686
"backends.tests.ThreadTests.test_default_connection_thread_local",
8787
# AlterField
8888
"schema.tests.SchemaTests.test_alter_auto_field_to_integer_field",
89-
"schema.tests.SchemaTests.test_alter_field_add_index_to_integerfield",
9089
"schema.tests.SchemaTests.test_alter_field_default_dropped",
9190
"schema.tests.SchemaTests.test_alter_field_fk_to_o2o",
9291
"schema.tests.SchemaTests.test_alter_field_o2o_keeps_unique",
@@ -95,11 +94,9 @@ class DatabaseFeatures(BaseDatabaseFeatures):
9594
"schema.tests.SchemaTests.test_alter_null_to_not_null",
9695
"schema.tests.SchemaTests.test_alter_primary_key_the_same_name",
9796
"schema.tests.SchemaTests.test_autofield_to_o2o",
98-
# AlterField (db_index)
99-
"schema.tests.SchemaTests.test_indexes",
10097
"schema.tests.SchemaTests.test_remove_constraints_capital_letters",
101-
"schema.tests.SchemaTests.test_remove_db_index_doesnt_remove_custom_indexes",
10298
# AlterField (unique)
99+
"schema.tests.SchemaTests.test_indexes",
103100
"schema.tests.SchemaTests.test_unique",
104101
"schema.tests.SchemaTests.test_unique_and_reverse_m2m",
105102
# alter_unique_together

django_mongodb/schema.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,59 @@ def _alter_field(
6868
new_db_params,
6969
strict=False,
7070
):
71+
# Removed an index? (no strict check, as multiple indexes are possible)
72+
# Remove indexes if db_index switched to False or a unique constraint
73+
# will now be used in lieu of an index. The following lines from the
74+
# truth table show all True cases; the rest are False:
75+
#
76+
# old_field.db_index | old_field.unique | new_field.db_index | new_field.unique
77+
# ------------------------------------------------------------------------------
78+
# True | False | False | False
79+
# True | False | False | True
80+
# True | False | True | True
81+
if (
82+
old_field.db_index
83+
and not old_field.unique
84+
and (not new_field.db_index or new_field.unique)
85+
):
86+
# Find the index for this field
87+
meta_index_names = {index.name for index in model._meta.indexes}
88+
# Retrieve only BTREE indexes since this is what's created with
89+
# db_index=True.
90+
index_names = self._constraint_names(
91+
model,
92+
[old_field.column],
93+
index=True,
94+
type_=Index.suffix,
95+
exclude=meta_index_names,
96+
)
97+
for index_name in index_names:
98+
# The only way to check if an index was created with
99+
# db_index=True or with Index(['field'], name='foo')
100+
# is to look at its name (refs #28053).
101+
self.connection.database[model._meta.db_table].drop_index(index_name)
71102
# Have they renamed the column?
72103
if old_field.column != new_field.column:
73104
self.connection.database[model._meta.db_table].update_many(
74105
{}, {"$rename": {old_field.column: new_field.column}}
75106
)
107+
# Added an index? Add an index if db_index switched to True or a unique
108+
# constraint will no longer be used in lieu of an index. The following
109+
# lines from the truth table show all True cases; the rest are False:
110+
#
111+
# old_field.db_index | old_field.unique | new_field.db_index | new_field.unique
112+
# ------------------------------------------------------------------------------
113+
# False | False | True | False
114+
# False | True | True | False
115+
# True | True | True | False
116+
if (
117+
(not old_field.db_index or old_field.unique)
118+
and new_field.db_index
119+
and not new_field.unique
120+
):
121+
index = Index(fields=[new_field.name])
122+
index.name = self._create_index_name(model._meta.db_table, [new_field.column])
123+
self.add_index(model, index)
76124

77125
def remove_field(self, model, field):
78126
# Remove implicit M2M tables.

0 commit comments

Comments
 (0)