Skip to content

Commit 370460d

Browse files
authored
Merge pull request #2897 from bagerard/terencehonles-fix-generic-reference-iterable-query
[Terencehonles fix] generic reference iterable query
2 parents 1b2afb6 + 2156e2c commit 370460d

File tree

5 files changed

+421
-334
lines changed

5 files changed

+421
-334
lines changed

docs/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Changelog
77
Development
88
===========
99
- (Fill this out as you fix issues and develop your features).
10+
- Fix querying GenericReferenceField with __in operator #2886
1011
- Fix Document.compare_indexes() not working correctly for text indexes on multiple fields #2612
1112
- Add support for transaction through run_in_transaction (kudos to juannyG for this) #2569
1213
Some considerations:

mongoengine/queryset/transform.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,15 @@ def query(_doc_cls=None, **kwargs):
129129

130130
singular_ops = [None, "ne", "gt", "gte", "lt", "lte", "not"]
131131
singular_ops += STRING_OPERATORS
132+
is_iterable = False
132133
if op in singular_ops:
133134
value = field.prepare_query_value(op, value)
134135

135136
if isinstance(field, CachedReferenceField) and value:
136137
value = value["_id"]
137138

138139
elif op in ("in", "nin", "all", "near") and not isinstance(value, dict):
140+
is_iterable = True
139141
# Raise an error if the in/nin/all/near param is not iterable.
140142
value = _prepare_query_for_iterable(field, op, value)
141143

@@ -144,10 +146,24 @@ def query(_doc_cls=None, **kwargs):
144146
# * If the value is a DBRef, the key should be "field_name._ref".
145147
# * If the value is an ObjectId, the key should be "field_name._ref.$id".
146148
if isinstance(field, GenericReferenceField):
147-
if isinstance(value, DBRef):
149+
if isinstance(value, DBRef) or (
150+
is_iterable and all(isinstance(v, DBRef) for v in value)
151+
):
148152
parts[-1] += "._ref"
149-
elif isinstance(value, ObjectId):
153+
elif isinstance(value, ObjectId) or (
154+
is_iterable and all(isinstance(v, ObjectId) for v in value)
155+
):
150156
parts[-1] += "._ref.$id"
157+
elif (
158+
is_iterable
159+
and any(isinstance(v, DBRef) for v in value)
160+
and any(isinstance(v, ObjectId) for v in value)
161+
):
162+
raise ValueError(
163+
"The `in`, `nin`, `all`, or `near`-operators cannot "
164+
"be applied to mixed queries of DBRef/ObjectId/%s"
165+
% _doc_cls.__name__
166+
)
151167

152168
# if op and op not in COMPARISON_OPERATORS:
153169
if op:

0 commit comments

Comments
 (0)