@@ -66,15 +66,52 @@ def _alter_field(
66
66
strict = False ,
67
67
):
68
68
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 )
69
85
# Have they renamed the column?
70
86
if old_field .column != new_field .column :
71
87
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 )
72
94
# Replace NULL with the field default if the field and was changed from
73
95
# NULL to NOT NULL.
74
96
if new_field .has_default () and old_field .null and not new_field .null :
75
97
column = new_field .column
76
98
default = self .effective_default (new_field )
77
99
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 )
78
115
79
116
def remove_field (self , model , field ):
80
117
# Remove implicit M2M tables.
@@ -152,6 +189,27 @@ def _remove_composed_index(self, model, field_names, constraint_kwargs):
152
189
collection = self .connection .database [model ._meta .db_table ]
153
190
collection .drop_index (constraint_names [0 ])
154
191
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
+
155
213
def add_constraint (self , model , constraint ):
156
214
pass
157
215
0 commit comments