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,8 +14,8 @@ 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
@@ -25,11 +25,21 @@ def _create_model_indexes(self, model):
2525 index = Index (fields = [field .name ])
2626 index .name = self ._create_index_name (model ._meta .db_table , [field .column ])
2727 self .add_index (model , index )
28+ # Field uniques
29+ for field in model ._meta .local_fields :
30+ if field .unique and field .column != "_id" :
31+ constraint = UniqueConstraint (
32+ fields = [field .name ], name = f"{ model ._meta .db_table } _{ field .column } _key"
33+ )
34+ self .add_constraint (model , constraint )
2835 # Meta.index_together (RemovedInDjango51Warning)
2936 for field_names in model ._meta .index_together :
3037 index = Index (fields = field_names )
3138 index .set_name_with_model (model )
3239 self .add_index (model , index )
40+ # Meta.constraints
41+ for constraint in model ._meta .constraints :
42+ self .add_constraint (model , constraint )
3343 # Meta.indexes
3444 for index in model ._meta .indexes :
3545 self .add_index (model , index )
@@ -56,6 +66,11 @@ def add_field(self, model, field):
5666 index = Index (fields = [field .name ])
5767 index .name = self ._create_index_name (model ._meta .db_table , [field .column ])
5868 self .add_index (model , index , field = field )
69+ if field .unique and field .column != "_id" :
70+ constraint = UniqueConstraint (
71+ fields = [field .name ], name = f"{ model ._meta .db_table } _{ field .column } _key"
72+ )
73+ self .add_constraint (model , constraint , field = field )
5974
6075 def _alter_field (
6176 self ,
@@ -148,9 +163,19 @@ def alter_index_together(self, model, old_index_together, new_index_together):
148163 def alter_unique_together (self , model , old_unique_together , new_unique_together ):
149164 pass
150165
151- def add_index (self , model , index , field = None ):
166+ def add_index (self , model , index , field = None , unique = False ):
152167 if index .contains_expressions :
153168 return
169+ kwargs = {}
170+ if unique :
171+ filter_expression = {}
172+ if field :
173+ filter_expression [field .column ] = {"$type" : field .db_type (self .connection )}
174+ else :
175+ for field_name , _ in index .fields_orders :
176+ field_ = model ._meta .get_field (field_name )
177+ filter_expression [field_ .column ] = {"$type" : field_ .db_type (self .connection )}
178+ kwargs = {"partialFilterExpression" : filter_expression , "unique" : True }
154179 index_orders = (
155180 [(field .column , 1 )]
156181 if field
@@ -162,6 +187,7 @@ def add_index(self, model, index, field=None):
162187 idx = IndexModel (
163188 index_orders ,
164189 name = index .name ,
190+ ** kwargs ,
165191 )
166192 self .connection .database [model ._meta .db_table ].create_indexes ([idx ])
167193
@@ -170,11 +196,27 @@ def remove_index(self, model, index):
170196 return
171197 self .connection .database [model ._meta .db_table ].drop_index (index .name )
172198
173- def add_constraint (self , model , constraint ):
174- pass
199+ def add_constraint (self , model , constraint , field = None ):
200+ if isinstance (constraint , UniqueConstraint ) and self ._unique_supported (
201+ condition = constraint .condition ,
202+ deferrable = constraint .deferrable ,
203+ include = constraint .include ,
204+ expressions = constraint .expressions ,
205+ nulls_distinct = constraint .nulls_distinct ,
206+ ):
207+ idx = Index (fields = constraint .fields , name = constraint .name )
208+ self .add_index (model , idx , field = field , unique = True )
175209
176210 def remove_constraint (self , model , constraint ):
177- pass
211+ if isinstance (constraint , UniqueConstraint ) and self ._unique_supported (
212+ condition = constraint .condition ,
213+ deferrable = constraint .deferrable ,
214+ include = constraint .include ,
215+ expressions = constraint .expressions ,
216+ nulls_distinct = constraint .nulls_distinct ,
217+ ):
218+ idx = Index (fields = constraint .fields , name = constraint .name )
219+ self .remove_index (model , idx )
178220
179221 def alter_db_table (self , model , old_db_table , new_db_table ):
180222 if old_db_table == new_db_table :
0 commit comments