1+ from time import monotonic , sleep
2+
13from django .db .backends .base .schema import BaseDatabaseSchemaEditor
24from django .db .models import Index , UniqueConstraint
35from pymongo .operations import SearchIndexModel
@@ -269,10 +271,12 @@ def add_index(
269271 )
270272 if idx :
271273 model = parent_model or model
274+ collection = self .get_collection (model ._meta .db_table )
272275 if isinstance (idx , SearchIndexModel ):
273- self .get_collection (model ._meta .db_table ).create_search_index (idx )
276+ collection .create_search_index (idx )
277+ self .wait_until_index_created (collection , index .name )
274278 else :
275- self . get_collection ( model . _meta . db_table ) .create_indexes ([idx ])
279+ collection .create_indexes ([idx ])
276280
277281 def _add_composed_index (self , model , field_names , column_prefix = "" , parent_model = None ):
278282 """Add an index on the given list of field_names."""
@@ -290,12 +294,14 @@ def _add_field_index(self, model, field, *, column_prefix=""):
290294 def remove_index (self , model , index ):
291295 if index .contains_expressions :
292296 return
297+ collection = self .get_collection (model ._meta .db_table )
293298 if isinstance (index , SearchIndex ):
294299 # Drop the index if it's supported.
295300 if self .connection .features .supports_atlas_search :
296- self .get_collection (model ._meta .db_table ).drop_search_index (index .name )
301+ collection .drop_search_index (index .name )
302+ self .wait_until_index_deleted (collection , index .name )
297303 else :
298- self . get_collection ( model . _meta . db_table ) .drop_index (index .name )
304+ collection .drop_index (index .name )
299305
300306 def _remove_composed_index (
301307 self , model , field_names , constraint_kwargs , column_prefix = "" , parent_model = None
@@ -420,6 +426,27 @@ def _field_should_have_unique(self, field):
420426 # The _id column is automatically unique.
421427 return db_type and field .unique and field .column != "_id"
422428
429+ @staticmethod
430+ def wait_until_index_created (collection , index_name , timeout = 60 , interval = 0.5 ):
431+ start = monotonic ()
432+ while monotonic () - start < timeout :
433+ indexes = list (collection .list_search_indexes ())
434+ for idx in indexes :
435+ if idx ["name" ] == index_name and idx ["status" ] == "READY" :
436+ return True
437+ sleep (interval )
438+ raise TimeoutError (f"Index { index_name } not ready after { timeout } seconds." )
439+
440+ @staticmethod
441+ def wait_until_index_deleted (collection , index_name , timeout = 60 , interval = 0.5 ):
442+ start = monotonic ()
443+ while monotonic () - start < timeout :
444+ indexes = list (collection .list_search_indexes ())
445+ if all (idx ["name" ] != index_name for idx in indexes ):
446+ return True
447+ sleep (interval )
448+ raise TimeoutError (f"Index { index_name } not deleted after { timeout } seconds." )
449+
423450
424451# GISSchemaEditor extends some SchemaEditor methods.
425452class DatabaseSchemaEditor (GISSchemaEditor , BaseSchemaEditor ):
0 commit comments