1+ from collections import defaultdict
2+
13from django .db import NotSupportedError
24from django .db .models import Index
35from django .db .models .lookups import BuiltinLookup
46from django .db .models .sql .query import Query
57from django .db .models .sql .where import AND , XOR , WhereNode
8+ from pymongo import ASCENDING , DESCENDING
9+ from pymongo .operations import IndexModel
610
711from .query_utils import process_rhs
812
@@ -36,6 +40,45 @@ def builtin_lookup_idx(self, compiler, connection):
3640 return {lhs_mql : {operator : value }}
3741
3842
43+ def get_pymongo_index_model (self , model , schema_editor , field = None , unique = False , column_prefix = "" ):
44+ """Return a pymongo IndexModel for this Django Index."""
45+ if self .contains_expressions :
46+ return None
47+ kwargs = {}
48+ filter_expression = defaultdict (dict )
49+ if self .condition :
50+ filter_expression .update (self ._get_condition_mql (model , schema_editor ))
51+ if unique :
52+ kwargs ["unique" ] = True
53+ # Indexing on $type matches the value of most SQL databases by
54+ # allowing multiple null values for the unique constraint.
55+ if field :
56+ column = column_prefix + field .column
57+ filter_expression [column ].update ({"$type" : field .db_type (schema_editor .connection )})
58+ else :
59+ for field_name , _ in self .fields_orders :
60+ field_ = model ._meta .get_field (field_name )
61+ filter_expression [field_ .column ].update (
62+ {"$type" : field_ .db_type (schema_editor .connection )}
63+ )
64+ if filter_expression :
65+ kwargs ["partialFilterExpression" ] = filter_expression
66+ index_orders = (
67+ [(column_prefix + field .column , ASCENDING )]
68+ if field
69+ else [
70+ # order is "" if ASCENDING or "DESC" if DESCENDING (see
71+ # django.db.models.indexes.Index.fields_orders).
72+ (
73+ column_prefix + model ._meta .get_field (field_name ).column ,
74+ ASCENDING if order == "" else DESCENDING ,
75+ )
76+ for field_name , order in self .fields_orders
77+ ]
78+ )
79+ return IndexModel (index_orders , name = self .name , ** kwargs )
80+
81+
3982def where_node_idx (self , compiler , connection ):
4083 if self .connector == AND :
4184 operator = "$and"
@@ -61,4 +104,5 @@ def where_node_idx(self, compiler, connection):
61104def register_indexes ():
62105 BuiltinLookup .as_mql_idx = builtin_lookup_idx
63106 Index ._get_condition_mql = _get_condition_mql
107+ Index .get_pymongo_index_model = get_pymongo_index_model
64108 WhereNode .as_mql_idx = where_node_idx
0 commit comments