1
1
from django .db .backends .base .schema import BaseDatabaseSchemaEditor
2
- from django .db .models import Index
2
+ from django .db .models import Index , UniqueConstraint
3
3
from pymongo .operations import IndexModel
4
4
5
5
@@ -14,20 +14,30 @@ def create_model(self, model):
14
14
15
15
def _create_model_indexes (self , model ):
16
16
"""
17
- Create all indexes (field indexes, index_together, Meta.indexes) for
18
- the specified model.
17
+ Create all indexes (field indexes & uniques , index_together,
18
+ Meta.constraints, Meta.indexes) for the specified model.
19
19
"""
20
20
if not model ._meta .managed or model ._meta .proxy or model ._meta .swapped :
21
21
return
22
22
# Field indexes
23
23
for field in model ._meta .local_fields :
24
24
if self ._field_should_be_indexed (model , field ):
25
25
self ._add_index_for_field (model , field )
26
+ # Field uniques
27
+ for field in model ._meta .local_fields :
28
+ if field .unique and field .column != "_id" :
29
+ constraint = UniqueConstraint (
30
+ fields = [field .name ], name = f"{ model ._meta .db_table } _{ field .column } _key"
31
+ )
32
+ self .add_constraint (model , constraint )
26
33
# Meta.index_together (RemovedInDjango51Warning)
27
34
for field_names in model ._meta .index_together :
28
35
index = Index (fields = field_names )
29
36
index .set_name_with_model (model )
30
37
self .add_index (model , index )
38
+ # Meta.constraints
39
+ for constraint in model ._meta .constraints :
40
+ self .add_constraint (model , constraint )
31
41
# Meta.indexes
32
42
for index in model ._meta .indexes :
33
43
self .add_index (model , index )
@@ -52,6 +62,11 @@ def add_field(self, model, field):
52
62
# Add an index, if required.
53
63
if self ._field_should_be_indexed (model , field ):
54
64
self ._add_index_for_field (model , field )
65
+ if field .unique and field .column != "_id" :
66
+ constraint = UniqueConstraint (
67
+ fields = [field .name ], name = f"{ model ._meta .db_table } _{ field .column } _key"
68
+ )
69
+ self .add_constraint (model , constraint , field = field )
55
70
56
71
def _add_index_for_field (self , model , field ):
57
72
new_index = Index (fields = [field .name ])
@@ -164,9 +179,19 @@ def alter_index_together(self, model, old_index_together, new_index_together):
164
179
def alter_unique_together (self , model , old_unique_together , new_unique_together ):
165
180
pass
166
181
167
- def add_index (self , model , index , field = None ):
182
+ def add_index (self , model , index , field = None , unique = False ):
168
183
if index .contains_expressions :
169
184
return
185
+ kwargs = {}
186
+ if unique :
187
+ filter_expression = {}
188
+ if field :
189
+ filter_expression [field .column ] = {"$type" : field .db_type (self .connection )}
190
+ else :
191
+ for field_name , _ in index .fields_orders :
192
+ field_ = model ._meta .get_field (field_name )
193
+ filter_expression [field_ .column ] = {"$type" : field_ .db_type (self .connection )}
194
+ kwargs = {"partialFilterExpression" : filter_expression , "unique" : True }
170
195
index_orders = (
171
196
[(field .column , 1 )]
172
197
if field
@@ -178,6 +203,7 @@ def add_index(self, model, index, field=None):
178
203
idx = IndexModel (
179
204
index_orders ,
180
205
name = index .name ,
206
+ ** kwargs ,
181
207
)
182
208
self .connection .database [model ._meta .db_table ].create_indexes ([idx ])
183
209
@@ -186,11 +212,27 @@ def remove_index(self, model, index):
186
212
return
187
213
self .connection .database [model ._meta .db_table ].drop_index (index .name )
188
214
189
- def add_constraint (self , model , constraint ):
190
- pass
215
+ def add_constraint (self , model , constraint , field = None ):
216
+ if isinstance (constraint , UniqueConstraint ) and self ._unique_supported (
217
+ condition = constraint .condition ,
218
+ deferrable = constraint .deferrable ,
219
+ include = constraint .include ,
220
+ expressions = constraint .expressions ,
221
+ nulls_distinct = constraint .nulls_distinct ,
222
+ ):
223
+ idx = Index (fields = constraint .fields , name = constraint .name )
224
+ self .add_index (model , idx , field = field , unique = True )
191
225
192
226
def remove_constraint (self , model , constraint ):
193
- pass
227
+ if isinstance (constraint , UniqueConstraint ) and self ._unique_supported (
228
+ condition = constraint .condition ,
229
+ deferrable = constraint .deferrable ,
230
+ include = constraint .include ,
231
+ expressions = constraint .expressions ,
232
+ nulls_distinct = constraint .nulls_distinct ,
233
+ ):
234
+ idx = Index (fields = constraint .fields , name = constraint .name )
235
+ self .remove_index (model , idx )
194
236
195
237
def alter_db_table (self , model , old_db_table , new_db_table ):
196
238
if old_db_table == new_db_table :
0 commit comments