Skip to content

Commit 2e3cbc3

Browse files
committed
add index creation/deletion support to SchemaEditor.alter_field()
1 parent ec39612 commit 2e3cbc3

File tree

2 files changed

+59
-5
lines changed

2 files changed

+59
-5
lines changed

django_mongodb/features.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,12 @@ class DatabaseFeatures(BaseDatabaseFeatures):
7979
# AddField
8080
"schema.tests.SchemaTests.test_add_unique_charfield",
8181
# AlterField
82-
"schema.tests.SchemaTests.test_alter_field_add_index_to_integerfield",
8382
"schema.tests.SchemaTests.test_alter_field_fk_to_o2o",
8483
"schema.tests.SchemaTests.test_alter_field_o2o_keeps_unique",
8584
"schema.tests.SchemaTests.test_alter_field_o2o_to_fk",
8685
"schema.tests.SchemaTests.test_alter_int_pk_to_int_unique",
87-
# AlterField (db_index)
88-
"schema.tests.SchemaTests.test_alter_renames_index",
89-
"schema.tests.SchemaTests.test_indexes",
90-
"schema.tests.SchemaTests.test_remove_db_index_doesnt_remove_custom_indexes",
9186
# AlterField (unique)
87+
"schema.tests.SchemaTests.test_indexes",
9288
"schema.tests.SchemaTests.test_unique",
9389
"schema.tests.SchemaTests.test_unique_and_reverse_m2m",
9490
# alter_unique_together

django_mongodb/schema.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,52 @@ def _alter_field(
6666
strict=False,
6767
):
6868
collection = self.connection.database[model._meta.db_table]
69+
# Removed an index? (no strict check, as multiple indexes are possible)
70+
# Remove indexes if db_index switched to False or a unique constraint
71+
# will now be used in lieu of an index. The following lines from the
72+
# truth table show all True cases; the rest are False:
73+
#
74+
# old_field.db_index | old_field.unique | new_field.db_index | new_field.unique
75+
# ------------------------------------------------------------------------------
76+
# True | False | False | False
77+
# True | False | False | True
78+
# True | False | True | True
79+
if (
80+
old_field.db_index
81+
and not old_field.unique
82+
and (not new_field.db_index or new_field.unique)
83+
):
84+
self._remove_field_index(model, old_field)
6985
# Have they renamed the column?
7086
if old_field.column != new_field.column:
7187
collection.update_many({}, {"$rename": {old_field.column: new_field.column}})
88+
# Move index to the new field, if needed.
89+
if self._field_should_be_indexed(model, old_field) and self._field_should_be_indexed(
90+
model, new_field
91+
):
92+
self._remove_field_index(model, old_field)
93+
self._add_field_index(model, new_field)
7294
# Replace NULL with the field default if the field and was changed from
7395
# NULL to NOT NULL.
7496
if new_field.has_default() and old_field.null and not new_field.null:
7597
column = new_field.column
7698
default = self.effective_default(new_field)
7799
collection.update_many({column: {"$eq": None}}, [{"$set": {column: default}}])
100+
# Added an index? Add an index if db_index switched to True or a unique
101+
# constraint will no longer be used in lieu of an index. The following
102+
# lines from the truth table show all True cases; the rest are False:
103+
#
104+
# old_field.db_index | old_field.unique | new_field.db_index | new_field.unique
105+
# ------------------------------------------------------------------------------
106+
# False | False | True | False
107+
# False | True | True | False
108+
# True | True | True | False
109+
if (
110+
(not old_field.db_index or old_field.unique)
111+
and new_field.db_index
112+
and not new_field.unique
113+
):
114+
self._add_field_index(model, new_field)
78115

79116
def remove_field(self, model, field):
80117
# Remove implicit M2M tables.
@@ -152,6 +189,27 @@ def _remove_composed_index(self, model, field_names, constraint_kwargs):
152189
collection = self.connection.database[model._meta.db_table]
153190
collection.drop_index(constraint_names[0])
154191

192+
def _remove_field_index(self, model, field):
193+
collection = self.connection.database[model._meta.db_table]
194+
# Find the index for this field
195+
meta_index_names = {index.name for index in model._meta.indexes}
196+
# Retrieve only BTREE indexes since this is what's created with
197+
# db_index=True.
198+
index_names = self._constraint_names(
199+
model,
200+
[field.column],
201+
index=True,
202+
type_=Index.suffix,
203+
exclude=meta_index_names,
204+
)
205+
if not index_names:
206+
raise ValueError(f"Index not found for {model._meta.db_table}.{field.column}.")
207+
for index_name in index_names:
208+
# The only way to check if an index was created with
209+
# db_index=True or with Index(['field'], name='foo')
210+
# is to look at its name (refs #28053).
211+
collection.drop_index(index_name)
212+
155213
def add_constraint(self, model, constraint):
156214
pass
157215

0 commit comments

Comments
 (0)