1
1
from django .db .backends .base .schema import BaseDatabaseSchemaEditor
2
+ from django .db .models import Index
3
+ from pymongo import ASCENDING , DESCENDING
4
+ from pymongo .operations import IndexModel
2
5
3
6
from .query import wrap_database_errors
4
7
from .utils import OperationCollector
@@ -18,11 +21,30 @@ def get_database(self):
18
21
@wrap_database_errors
19
22
def create_model (self , model ):
20
23
self .get_database ().create_collection (model ._meta .db_table )
24
+ self ._create_model_indexes (model )
21
25
# Make implicit M2M tables.
22
26
for field in model ._meta .local_many_to_many :
23
27
if field .remote_field .through ._meta .auto_created :
24
28
self .create_model (field .remote_field .through )
25
29
30
+ def _create_model_indexes (self , model ):
31
+ """
32
+ Create all indexes (field indexes, index_together, Meta.indexes) for
33
+ the specified model.
34
+ """
35
+ if not model ._meta .managed or model ._meta .proxy or model ._meta .swapped :
36
+ return
37
+ # Field indexes
38
+ for field in model ._meta .local_fields :
39
+ if self ._field_should_be_indexed (model , field ):
40
+ self ._add_field_index (model , field )
41
+ # Meta.index_together (RemovedInDjango51Warning)
42
+ for field_names in model ._meta .index_together :
43
+ self ._add_composed_index (model , field_names )
44
+ # Meta.indexes
45
+ for index in model ._meta .indexes :
46
+ self .add_index (model , index )
47
+
26
48
def delete_model (self , model ):
27
49
# Delete implicit M2m tables.
28
50
for field in model ._meta .local_many_to_many :
@@ -40,6 +62,9 @@ def add_field(self, model, field):
40
62
self .get_collection (model ._meta .db_table ).update_many (
41
63
{}, [{"$set" : {column : self .effective_default (field )}}]
42
64
)
65
+ # Add an index, if required.
66
+ if self ._field_should_be_indexed (model , field ):
67
+ self ._add_field_index (model , field )
43
68
44
69
def _alter_field (
45
70
self ,
@@ -71,21 +96,68 @@ def remove_field(self, model, field):
71
96
# Unset field on existing documents.
72
97
if column := field .column :
73
98
self .get_collection (model ._meta .db_table ).update_many ({}, {"$unset" : {column : "" }})
99
+ if self ._field_should_be_indexed (model , field ):
100
+ self ._remove_field_index (model , field )
74
101
75
102
def alter_index_together (self , model , old_index_together , new_index_together ):
76
103
pass
77
104
78
105
def alter_unique_together (self , model , old_unique_together , new_unique_together ):
79
106
pass
80
107
81
- def add_index (self , model , index ):
82
- pass
83
-
84
- def rename_index (self , model , old_index , new_index ):
85
- pass
108
+ def add_index (self , model , index , field = None ):
109
+ if index .contains_expressions :
110
+ return
111
+ index_orders = (
112
+ [(field .column , ASCENDING )]
113
+ if field
114
+ else [
115
+ # order is "" if ASCENDING or "DESC" if DESCENDING (see
116
+ # django.db.models.indexes.Index.fields_orders).
117
+ (model ._meta .get_field (field_name ).column , ASCENDING if order == "" else DESCENDING )
118
+ for field_name , order in index .fields_orders
119
+ ]
120
+ )
121
+ idx = IndexModel (index_orders , name = index .name )
122
+ self .get_collection (model ._meta .db_table ).create_indexes ([idx ])
123
+
124
+ def _add_composed_index (self , model , field_names ):
125
+ """Add an index on the given list of field_names."""
126
+ idx = Index (fields = field_names )
127
+ idx .set_name_with_model (model )
128
+ self .add_index (model , idx )
129
+
130
+ def _add_field_index (self , model , field ):
131
+ """Add an index on a field with db_index=True."""
132
+ index = Index (fields = [field .name ])
133
+ index .name = self ._create_index_name (model ._meta .db_table , [field .column ])
134
+ self .add_index (model , index , field = field )
86
135
87
136
def remove_index (self , model , index ):
88
- pass
137
+ if index .contains_expressions :
138
+ return
139
+ self .get_collection (model ._meta .db_table ).drop_index (index .name )
140
+
141
+ def _remove_field_index (self , model , field ):
142
+ """Remove a field's db_index=True index."""
143
+ collection = self .get_collection (model ._meta .db_table )
144
+ meta_index_names = {index .name for index in model ._meta .indexes }
145
+ index_names = self ._constraint_names (
146
+ model ,
147
+ [field .column ],
148
+ index = True ,
149
+ # Retrieve only BTREE indexes since this is what's created with
150
+ # db_index=True.
151
+ type_ = Index .suffix ,
152
+ exclude = meta_index_names ,
153
+ )
154
+ if len (index_names ) != 1 :
155
+ num_found = len (index_names )
156
+ raise ValueError (
157
+ f"Found wrong number ({ num_found } ) of constraints for "
158
+ f"{ model ._meta .db_table } .{ field .column } ."
159
+ )
160
+ collection .drop_index (index_names [0 ])
89
161
90
162
def add_constraint (self , model , constraint ):
91
163
pass
0 commit comments