1
+ from time import monotonic , sleep
2
+
1
3
from django .db .backends .base .schema import BaseDatabaseSchemaEditor
2
4
from django .db .models import Index , UniqueConstraint
3
5
from pymongo .operations import SearchIndexModel
@@ -269,10 +271,12 @@ def add_index(
269
271
)
270
272
if idx :
271
273
model = parent_model or model
274
+ collection = self .get_collection (model ._meta .db_table )
272
275
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 )
274
278
else :
275
- self . get_collection ( model . _meta . db_table ) .create_indexes ([idx ])
279
+ collection .create_indexes ([idx ])
276
280
277
281
def _add_composed_index (self , model , field_names , column_prefix = "" , parent_model = None ):
278
282
"""Add an index on the given list of field_names."""
@@ -290,12 +294,14 @@ def _add_field_index(self, model, field, *, column_prefix=""):
290
294
def remove_index (self , model , index ):
291
295
if index .contains_expressions :
292
296
return
297
+ collection = self .get_collection (model ._meta .db_table )
293
298
if isinstance (index , SearchIndex ):
294
299
# Drop the index if it's supported.
295
300
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_dropped (collection , index .name )
297
303
else :
298
- self . get_collection ( model . _meta . db_table ) .drop_index (index .name )
304
+ collection .drop_index (index .name )
299
305
300
306
def _remove_composed_index (
301
307
self , model , field_names , constraint_kwargs , column_prefix = "" , parent_model = None
@@ -420,6 +426,32 @@ def _field_should_have_unique(self, field):
420
426
# The _id column is automatically unique.
421
427
return db_type and field .unique and field .column != "_id"
422
428
429
+ @staticmethod
430
+ def wait_until_index_created (collection , index_name , timeout = 60 * 60 , interval = 0.5 ):
431
+ """
432
+ Wait up to an hour until an index is created. Index creation time
433
+ depends on the size of the collection being indexed.
434
+ """
435
+ start = monotonic ()
436
+ while monotonic () - start < timeout :
437
+ indexes = list (collection .list_search_indexes ())
438
+ for idx in indexes :
439
+ if idx ["name" ] == index_name and idx ["status" ] == "READY" :
440
+ return True
441
+ sleep (interval )
442
+ raise TimeoutError (f"Index { index_name } not ready after { timeout } seconds." )
443
+
444
+ @staticmethod
445
+ def wait_until_index_dropped (collection , index_name , timeout = 60 , interval = 0.5 ):
446
+ """Wait up to 60 seconds until an index is dropped."""
447
+ start = monotonic ()
448
+ while monotonic () - start < timeout :
449
+ indexes = list (collection .list_search_indexes ())
450
+ if all (idx ["name" ] != index_name for idx in indexes ):
451
+ return True
452
+ sleep (interval )
453
+ raise TimeoutError (f"Index { index_name } not dropped after { timeout } seconds." )
454
+
423
455
424
456
# GISSchemaEditor extends some SchemaEditor methods.
425
457
class DatabaseSchemaEditor (GISSchemaEditor , BaseSchemaEditor ):
0 commit comments