Skip to content

Commit 782feb7

Browse files
committed
INTPYTHON-599 Make a field's custom transforms available in embedded model queries
1 parent 6f8c322 commit 782feb7

File tree

4 files changed

+29
-41
lines changed

4 files changed

+29
-41
lines changed

django_mongodb_backend/fields/embedded_model.py

Lines changed: 16 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from django.db.models.lookups import Transform
88

99
from .. import forms
10-
from .json import build_json_mql_path
1110

1211

1312
class EmbeddedModelField(models.Field):
@@ -163,49 +162,29 @@ def get_transform(self, name):
163162
Validate that `name` is either a field of an embedded model or a
164163
lookup on an embedded model's field.
165164
"""
166-
result = None
167-
if isinstance(self.ref_field, EmbeddedModelField):
168-
opts = self.ref_field.embedded_model._meta
169-
new_field = opts.get_field(name)
170-
result = KeyTransformFactory(name, new_field)
165+
if transform := self.ref_field.get_transform(name):
166+
return transform
167+
suggested_lookups = difflib.get_close_matches(name, self.ref_field.get_lookups())
168+
if suggested_lookups:
169+
suggested_lookups = " or ".join(suggested_lookups)
170+
suggestion = f", perhaps you meant {suggested_lookups}?"
171171
else:
172-
if self.ref_field.get_transform(name) is None:
173-
suggested_lookups = difflib.get_close_matches(name, self.ref_field.get_lookups())
174-
if suggested_lookups:
175-
suggested_lookups = " or ".join(suggested_lookups)
176-
suggestion = f", perhaps you meant {suggested_lookups}?"
177-
else:
178-
suggestion = "."
179-
raise FieldDoesNotExist(
180-
f"Unsupported lookup '{name}' for "
181-
f"{self.ref_field.__class__.__name__} '{self.ref_field.name}'"
182-
f"{suggestion}"
183-
)
184-
result = KeyTransformFactory(name, self.ref_field)
185-
return result
172+
suggestion = "."
173+
raise FieldDoesNotExist(
174+
f"Unsupported lookup '{name}' for "
175+
f"{self.ref_field.__class__.__name__} '{self.ref_field.name}'"
176+
f"{suggestion}"
177+
)
186178

187-
def preprocess_lhs(self, compiler, connection):
179+
def as_mql(self, compiler, connection):
188180
previous = self
189-
embedded_key_transforms = []
190-
json_key_transforms = []
181+
key_transforms = []
191182
while isinstance(previous, KeyTransform):
192-
if isinstance(previous.ref_field, EmbeddedModelField):
193-
embedded_key_transforms.insert(0, previous.key_name)
194-
else:
195-
json_key_transforms.insert(0, previous.key_name)
183+
key_transforms.insert(0, previous.key_name)
196184
previous = previous.lhs
197185
mql = previous.as_mql(compiler, connection)
198-
# The first json_key_transform is the field name.
199-
embedded_key_transforms.append(json_key_transforms.pop(0))
200-
return mql, embedded_key_transforms, json_key_transforms
201-
202-
def as_mql(self, compiler, connection):
203-
mql, key_transforms, json_key_transforms = self.preprocess_lhs(compiler, connection)
204186
transforms = ".".join(key_transforms)
205-
result = f"{mql}.{transforms}"
206-
if json_key_transforms:
207-
result = build_json_mql_path(result, json_key_transforms)
208-
return result
187+
return f"{mql}.{transforms}"
209188

210189
@property
211190
def output_field(self):

docs/source/releases/5.1.x.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ Django MongoDB Backend 5.1.x
77

88
*Unreleased*
99

10-
- Added support for a field's custom lookups in ``EmbeddedModelField``, e.g.
11-
``ArrayField``’s ``contains``, ``contained__by``, etc.
10+
- Added support for a field's custom lookups and transforms in
11+
``EmbeddedModelField``, e.g. ``ArrayField``’s ``contains``,
12+
``contained__by``, ``len``, etc.
1213

1314
.. _django-mongodb-backend-5.1.0-beta-2:
1415

docs/source/releases/5.2.x.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ Regarding new features in Django 5.2,
1616
Bug fixes
1717
---------
1818

19-
- Added support for a field's custom lookups in ``EmbeddedModelField``, e.g.
20-
``ArrayField``’s ``contains``, ``contained__by``, etc.
19+
- Added support for a field's custom lookups and transforms in
20+
``EmbeddedModelField``, e.g. ``ArrayField``’s ``contains``,
21+
``contained__by``, ``len``, etc.

tests/model_fields_/test_embedded_model.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,13 @@ def test_contained_by(self):
228228
[self.book],
229229
)
230230

231+
def test_len(self):
232+
self.assertCountEqual(Book.objects.filter(author__skills__len=1), [])
233+
self.assertCountEqual(Book.objects.filter(author__skills__len=2), [self.book])
234+
# Nested
235+
self.assertCountEqual(Book.objects.filter(author__address__tags__len=1), [])
236+
self.assertCountEqual(Book.objects.filter(author__address__tags__len=2), [self.book])
237+
231238

232239
class InvalidLookupTests(SimpleTestCase):
233240
def test_invalid_field(self):

0 commit comments

Comments
 (0)