@@ -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