Skip to content

Commit 5d68dda

Browse files
committed
Handle F keystransform.
1 parent b10c6df commit 5d68dda

File tree

3 files changed

+35
-12
lines changed

3 files changed

+35
-12
lines changed

django_mongodb/features.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
375375
"model_fields.test_jsonfield.JSONFieldTests.test_db_check_constraints",
376376
},
377377
"Mongodb's Null behaviour is different from sql's": {
378-
"model_fields.test_jsonfield.TestQuerying.test_none_key_exclude",
379-
"model_fields.test_jsonfield.TestQuerying.test_isnull_key",
378+
"model_fields.test_jsonfield.TestQuerying.test_none_key_and_exact_lookup",
379+
# "model_fields.test_jsonfield.TestQuerying.test_isnull_key",
380380
},
381381
"Pipeline filtering": {"model_fields.test_jsonfield.TestQuerying.test_icontains"},
382382
}

django_mongodb/fields/auto.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,15 @@ def from_db_value(self, value, expression, connection):
6565
def json_process_rhs(node, compiler, connection):
6666
_, value = node.process_rhs(compiler, connection)
6767

68-
# Django's framework transform the [None] into a [null],
69-
# we have to revertit.
70-
if value == ["null"]:
71-
value = [None]
72-
7368
lookup_name = node.lookup_name
7469
if lookup_name not in ("in", "range"):
7570
value = value[0] if len(value) > 0 else []
71+
else:
72+
result_value = []
73+
for ind, elem in enumerate(node.rhs):
74+
item = f"${value[ind]}" if isinstance(elem, KeyTransform) else value[ind]
75+
result_value.append(item)
76+
value = result_value
7677

7778
return value
7879

@@ -96,24 +97,31 @@ def contained_by(self, compiler, connection): # noqa: ARG001
9697

9798

9899
def json_exact(self, compiler, connection):
99-
rhs_mql = json_process_rhs(self, compiler, connection)
100100
lhs_mql = process_lhs(self, compiler, connection)
101+
rhs_mql = json_process_rhs(self, compiler, connection)
102+
if rhs_mql == "null":
103+
return {"$or": [{lhs_mql: {"$eq": None}}, {lhs_mql: {"$exists": False}}]}
104+
# return {lhs_mql: {"$eq": None, "$exists": True}}
105+
# return key_transform_isnull(self, compiler, connection)
101106
return {lhs_mql: {"$eq": rhs_mql, "$exists": True}}
102107

103108

104109
def key_transform_isnull(self, compiler, connection):
105110
lhs_mql = process_lhs(self, compiler, connection)
106111
rhs_mql = json_process_rhs(self, compiler, connection)
107-
if rhs_mql is False:
108-
return {lhs_mql: {"$neq": None}}
109-
return {"$or": [{lhs_mql: {"$eq": None}}, {lhs_mql: {"$exists": False}}]}
112+
# if rhs_mql is False:
113+
# return {lhs_mql: {"$neq": None}}
114+
# return {"$or": [{lhs_mql: {"$eq": None}}, {lhs_mql: {"$exists": False}}]}
115+
116+
# https://code.djangoproject.com/ticket/32252
117+
return {lhs_mql: {"$exists": not rhs_mql}}
110118

111119

112120
def key_transform_in(self, compiler, connection):
113121
lhs_mql = process_lhs(self, compiler, connection)
114122
value = json_process_rhs(self, compiler, connection)
115123
rhs_mql = connection.operators[self.lookup_name](value)
116-
return {lhs_mql: rhs_mql}
124+
return {"$expr": {lhs_mql: rhs_mql}}
117125

118126

119127
def has_key_lookup(self, compiler, connection):

django_mongodb/lookups.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,23 @@ def uuid_text_mixin(self, compiler, connection): # noqa: ARG001
2828
raise NotSupportedError("Pattern lookups on UUIDField are not supported.")
2929

3030

31+
_resolve_expression_parameter = FieldGetDbPrepValueIterableMixin.resolve_expression_parameter
32+
33+
34+
def resolve_expression_parameter(self, compiler, connection, sql, param):
35+
if connection.vendor == "mongodb":
36+
params = [param]
37+
if hasattr(param, "resolve_expression"):
38+
param = param.resolve_expression(compiler.query)
39+
if hasattr(param, "as_mql"):
40+
params = [param.as_mql(compiler, connection)]
41+
return "", params
42+
return _resolve_expression_parameter(self, compiler, connection, sql, param)
43+
44+
3145
def register_lookups():
3246
BuiltinLookup.as_mql = builtin_lookup
3347
In.as_mql = RelatedIn.as_mql = in_
3448
IsNull.as_mql = is_null
3549
UUIDTextMixin.as_mql = uuid_text_mixin
50+
FieldGetDbPrepValueIterableMixin.resolve_expression_parameter = resolve_expression_parameter

0 commit comments

Comments
 (0)