5
5
from pymongo import ASCENDING , DESCENDING
6
6
from pymongo .operations import IndexModel
7
7
8
+ from .fields import EmbeddedModelField
8
9
from .query import wrap_database_errors
9
10
from .utils import OperationCollector
10
11
@@ -29,25 +30,40 @@ def create_model(self, model):
29
30
if field .remote_field .through ._meta .auto_created :
30
31
self .create_model (field .remote_field .through )
31
32
32
- def _create_model_indexes (self , model ):
33
+ def _create_model_indexes (self , model , column_prefix = "" , parent_model = None ):
33
34
"""
34
35
Create all indexes (field indexes & uniques, Meta.index_together,
35
36
Meta.unique_together, Meta.constraints, Meta.indexes) for the model.
37
+
38
+ If this is a recursive call to due to an embedded model, `column_prefix`
39
+ tracks the path that must be prepended to the index's column, and
40
+ `parent_model` tracks the collection to add the index/constraint to.
36
41
"""
37
42
if not model ._meta .managed or model ._meta .proxy or model ._meta .swapped :
38
43
return
39
44
# Field indexes and uniques
40
45
for field in model ._meta .local_fields :
46
+ if isinstance (field , EmbeddedModelField ):
47
+ new_path = f"{ column_prefix } { field .column } ."
48
+ self ._create_model_indexes (
49
+ field .embedded_model , parent_model = parent_model or model , column_prefix = new_path
50
+ )
41
51
if self ._field_should_be_indexed (model , field ):
42
- self ._add_field_index (model , field )
52
+ self ._add_field_index (parent_model or model , field , column_prefix = column_prefix )
43
53
elif self ._field_should_have_unique (field ):
44
- self ._add_field_unique (model , field )
54
+ self ._add_field_unique (parent_model or model , field , column_prefix = column_prefix )
45
55
# Meta.index_together (RemovedInDjango51Warning)
46
56
for field_names in model ._meta .index_together :
47
57
self ._add_composed_index (model , field_names )
48
58
# Meta.unique_together
49
59
if model ._meta .unique_together :
50
- self .alter_unique_together (model , [], model ._meta .unique_together )
60
+ self .alter_unique_together (
61
+ model ,
62
+ [],
63
+ model ._meta .unique_together ,
64
+ column_prefix = column_prefix ,
65
+ parent_model = parent_model ,
66
+ )
51
67
# Meta.constraints
52
68
for constraint in model ._meta .constraints :
53
69
self .add_constraint (model , constraint )
@@ -147,7 +163,9 @@ def alter_index_together(self, model, old_index_together, new_index_together):
147
163
for field_names in news .difference (olds ):
148
164
self ._add_composed_index (model , field_names )
149
165
150
- def alter_unique_together (self , model , old_unique_together , new_unique_together ):
166
+ def alter_unique_together (
167
+ self , model , old_unique_together , new_unique_together , column_prefix = "" , parent_model = None
168
+ ):
151
169
olds = {tuple (fields ) for fields in old_unique_together }
152
170
news = {tuple (fields ) for fields in new_unique_together }
153
171
# Deleted uniques
@@ -160,11 +178,19 @@ def alter_unique_together(self, model, old_unique_together, new_unique_together)
160
178
# Created uniques
161
179
for field_names in news .difference (olds ):
162
180
columns = [model ._meta .get_field (field ).column for field in field_names ]
163
- name = str (self ._unique_constraint_name (model ._meta .db_table , columns ))
181
+ name = str (
182
+ self ._unique_constraint_name (
183
+ model ._meta .db_table , [column_prefix + col for col in columns ]
184
+ )
185
+ )
164
186
constraint = UniqueConstraint (fields = field_names , name = name )
165
- self .add_constraint (model , constraint )
187
+ self .add_constraint (
188
+ model , constraint , parent_model = parent_model , column_prefix = column_prefix
189
+ )
166
190
167
- def add_index (self , model , index , field = None , unique = False ):
191
+ def add_index (
192
+ self , model , index , * , field = None , unique = False , column_prefix = "" , parent_model = None
193
+ ):
168
194
if index .contains_expressions :
169
195
return
170
196
kwargs = {}
@@ -176,7 +202,8 @@ def add_index(self, model, index, field=None, unique=False):
176
202
# Indexing on $type matches the value of most SQL databases by
177
203
# allowing multiple null values for the unique constraint.
178
204
if field :
179
- filter_expression [field .column ].update ({"$type" : field .db_type (self .connection )})
205
+ column = column_prefix + field .column
206
+ filter_expression [column ].update ({"$type" : field .db_type (self .connection )})
180
207
else :
181
208
for field_name , _ in index .fields_orders :
182
209
field_ = model ._meta .get_field (field_name )
@@ -186,16 +213,20 @@ def add_index(self, model, index, field=None, unique=False):
186
213
if filter_expression :
187
214
kwargs ["partialFilterExpression" ] = filter_expression
188
215
index_orders = (
189
- [(field .column , ASCENDING )]
216
+ [(column_prefix + field .column , ASCENDING )]
190
217
if field
191
218
else [
192
219
# order is "" if ASCENDING or "DESC" if DESCENDING (see
193
220
# django.db.models.indexes.Index.fields_orders).
194
- (model ._meta .get_field (field_name ).column , ASCENDING if order == "" else DESCENDING )
221
+ (
222
+ column_prefix + model ._meta .get_field (field_name ).column ,
223
+ ASCENDING if order == "" else DESCENDING ,
224
+ )
195
225
for field_name , order in index .fields_orders
196
226
]
197
227
)
198
228
idx = IndexModel (index_orders , name = index .name , ** kwargs )
229
+ model = parent_model or model
199
230
self .get_collection (model ._meta .db_table ).create_indexes ([idx ])
200
231
201
232
def _add_composed_index (self , model , field_names ):
@@ -204,11 +235,11 @@ def _add_composed_index(self, model, field_names):
204
235
idx .set_name_with_model (model )
205
236
self .add_index (model , idx )
206
237
207
- def _add_field_index (self , model , field ):
238
+ def _add_field_index (self , model , field , * , column_prefix = "" ):
208
239
"""Add an index on a field with db_index=True."""
209
- index = Index (fields = [field .name ])
210
- index .name = self ._create_index_name (model ._meta .db_table , [field .column ])
211
- self .add_index (model , index , field = field )
240
+ index = Index (fields = [column_prefix + field .name ])
241
+ index .name = self ._create_index_name (model ._meta .db_table , [column_prefix + field .column ])
242
+ self .add_index (model , index , field = field , column_prefix = column_prefix )
212
243
213
244
def remove_index (self , model , index ):
214
245
if index .contains_expressions :
@@ -260,7 +291,7 @@ def _remove_field_index(self, model, field):
260
291
)
261
292
collection .drop_index (index_names [0 ])
262
293
263
- def add_constraint (self , model , constraint , field = None ):
294
+ def add_constraint (self , model , constraint , field = None , column_prefix = "" , parent_model = None ):
264
295
if isinstance (constraint , UniqueConstraint ) and self ._unique_supported (
265
296
condition = constraint .condition ,
266
297
deferrable = constraint .deferrable ,
@@ -273,12 +304,21 @@ def add_constraint(self, model, constraint, field=None):
273
304
name = constraint .name ,
274
305
condition = constraint .condition ,
275
306
)
276
- self .add_index (model , idx , field = field , unique = True )
307
+ self .add_index (
308
+ model ,
309
+ idx ,
310
+ field = field ,
311
+ unique = True ,
312
+ column_prefix = column_prefix ,
313
+ parent_model = parent_model ,
314
+ )
277
315
278
- def _add_field_unique (self , model , field ):
279
- name = str (self ._unique_constraint_name (model ._meta .db_table , [field .column ]))
316
+ def _add_field_unique (self , model , field , column_prefix = "" ):
317
+ name = str (
318
+ self ._unique_constraint_name (model ._meta .db_table , [column_prefix + field .column ])
319
+ )
280
320
constraint = UniqueConstraint (fields = [field .name ], name = name )
281
- self .add_constraint (model , constraint , field = field )
321
+ self .add_constraint (model , constraint , field = field , column_prefix = column_prefix )
282
322
283
323
def remove_constraint (self , model , constraint ):
284
324
if isinstance (constraint , UniqueConstraint ) and self ._unique_supported (
0 commit comments