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