1
+ from collections import defaultdict
2
+
1
3
from django .db import NotSupportedError
2
4
from django .db .models import Index
3
5
from django .db .models .lookups import BuiltinLookup
4
6
from django .db .models .sql .query import Query
5
7
from django .db .models .sql .where import AND , XOR , WhereNode
8
+ from pymongo import ASCENDING , DESCENDING
9
+ from pymongo .operations import IndexModel
6
10
7
11
from .query_utils import process_rhs
8
12
@@ -36,6 +40,45 @@ def builtin_lookup_idx(self, compiler, connection):
36
40
return {lhs_mql : {operator : value }}
37
41
38
42
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
+
39
82
def where_node_idx (self , compiler , connection ):
40
83
if self .connector == AND :
41
84
operator = "$and"
@@ -61,4 +104,5 @@ def where_node_idx(self, compiler, connection):
61
104
def register_indexes ():
62
105
BuiltinLookup .as_mql_idx = builtin_lookup_idx
63
106
Index ._get_condition_mql = _get_condition_mql
107
+ Index .get_pymongo_index_model = get_pymongo_index_model
64
108
WhereNode .as_mql_idx = where_node_idx
0 commit comments