11from django .db .backends .base .schema import BaseDatabaseSchemaEditor
2- from django .db .models import Index
2+ from django .db .models import Index , UniqueConstraint
33from pymongo .operations import IndexModel
44
55
@@ -14,20 +14,30 @@ def create_model(self, model):
1414
1515 def _create_model_indexes (self , model ):
1616 """
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.
1919 """
2020 if not model ._meta .managed or model ._meta .proxy or model ._meta .swapped :
2121 return
2222 # Field indexes
2323 for field in model ._meta .local_fields :
2424 if self ._field_should_be_indexed (model , field ):
2525 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 )
2633 # Meta.index_together (RemovedInDjango51Warning)
2734 for field_names in model ._meta .index_together :
2835 index = Index (fields = field_names )
2936 index .set_name_with_model (model )
3037 self .add_index (model , index )
38+ # Meta.constraints
39+ for constraint in model ._meta .constraints :
40+ self .add_constraint (model , constraint )
3141 # Meta.indexes
3242 for index in model ._meta .indexes :
3343 self .add_index (model , index )
@@ -52,6 +62,11 @@ def add_field(self, model, field):
5262 # Add an index, if required.
5363 if self ._field_should_be_indexed (model , field ):
5464 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 )
5570
5671 def _add_index_for_field (self , model , field ):
5772 new_index = Index (fields = [field .name ])
@@ -164,9 +179,19 @@ def alter_index_together(self, model, old_index_together, new_index_together):
164179 def alter_unique_together (self , model , old_unique_together , new_unique_together ):
165180 pass
166181
167- def add_index (self , model , index , field = None ):
182+ def add_index (self , model , index , field = None , unique = False ):
168183 if index .contains_expressions :
169184 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 }
170195 index_orders = (
171196 [(field .column , 1 )]
172197 if field
@@ -178,6 +203,7 @@ def add_index(self, model, index, field=None):
178203 idx = IndexModel (
179204 index_orders ,
180205 name = index .name ,
206+ ** kwargs ,
181207 )
182208 self .connection .database [model ._meta .db_table ].create_indexes ([idx ])
183209
@@ -186,11 +212,27 @@ def remove_index(self, model, index):
186212 return
187213 self .connection .database [model ._meta .db_table ].drop_index (index .name )
188214
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 )
191225
192226 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 )
194236
195237 def alter_db_table (self , model , old_db_table , new_db_table ):
196238 if old_db_table == new_db_table :
0 commit comments