Skip to content

Commit 34e7cd7

Browse files
committed
add_raw__order_by
1 parent cfb4265 commit 34e7cd7

File tree

4 files changed

+46
-3
lines changed

4 files changed

+46
-3
lines changed

docs/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Development
1616
- BREAKING CHANGE: no_dereference context manager no longer returns the class in __enter__ #2788
1717
as it was useless and making it look like it was returning a different class although it was the same.
1818
Thus, it must be called like `with no_dereference(User):` and no longer `with no_dereference(User) as ...:`
19+
- Added __raw__ to :meth:`~mongoengine.Queryset.order_by()` to allow to provide raw pymongo 'sort' argument and get around some of the limitations #2783
1920

2021
Changes in 0.27.0
2122
=================

mongoengine/context_managers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"query_counter",
1717
"set_write_concern",
1818
"set_read_write_concern",
19+
"no_dereferencing_active_for_class",
1920
)
2021

2122

mongoengine/queryset/base.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,7 +1113,7 @@ def all_fields(self):
11131113
)
11141114
return queryset
11151115

1116-
def order_by(self, *keys):
1116+
def order_by(self, *keys, __raw__=None):
11171117
"""Order the :class:`~mongoengine.queryset.QuerySet` by the given keys.
11181118
11191119
The order may be specified by prepending each of the keys by a "+" or
@@ -1123,11 +1123,19 @@ def order_by(self, *keys):
11231123
11241124
:param keys: fields to order the query results by; keys may be
11251125
prefixed with "+" or a "-" to determine the ordering direction.
1126+
:param __raw__: a raw pymongo "sort" argument (provided as a list of (key, direction))
1127+
see 'key_or_list' in `pymongo.cursor.Cursor.sort doc <https://pymongo.readthedocs.io/en/stable/api/pymongo/cursor.html#pymongo.cursor.Cursor.sort>`.
1128+
If both keys and __raw__ are provided, an exception is raised
11261129
"""
1127-
queryset = self.clone()
1130+
if __raw__ and keys:
1131+
raise OperationError("Can not use both keys and __raw__ with order_by() ")
11281132

1133+
queryset = self.clone()
11291134
old_ordering = queryset._ordering
1130-
new_ordering = queryset._get_order_by(keys)
1135+
if __raw__:
1136+
new_ordering = __raw__
1137+
else:
1138+
new_ordering = queryset._get_order_by(keys)
11311139

11321140
if queryset._cursor_obj:
11331141
# If a cursor object has already been created, apply the sort to it

tests/queryset/test_queryset.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,6 +2680,39 @@ def test_order_by_chaining(self):
26802680
ages = [p.age for p in qs]
26812681
assert ages == [40, 30, 20]
26822682

2683+
def test_order_by_using_raw(self):
2684+
person_a = self.Person(name="User A", age=20)
2685+
person_a.save()
2686+
person_b = self.Person(name="User B", age=30)
2687+
person_b.save()
2688+
person_c = self.Person(name="User B", age=25)
2689+
person_c.save()
2690+
person_d = self.Person(name="User C", age=40)
2691+
person_d.save()
2692+
2693+
qs = self.Person.objects.order_by(__raw__=[("name", pymongo.DESCENDING)])
2694+
assert qs._ordering == [("name", pymongo.DESCENDING)]
2695+
names = [p.name for p in qs]
2696+
assert names == ["User C", "User B", "User B", "User A"]
2697+
2698+
names = [
2699+
(p.name, p.age)
2700+
for p in self.Person.objects.order_by(__raw__=[("name", pymongo.ASCENDING)])
2701+
]
2702+
assert names == [("User A", 20), ("User B", 30), ("User B", 25), ("User C", 40)]
2703+
2704+
names = [
2705+
(p.name, p.age)
2706+
for p in self.Person.objects.order_by(
2707+
__raw__=["name", ("age", pymongo.ASCENDING)]
2708+
)
2709+
]
2710+
assert names == [("User A", 20), ("User B", 25), ("User B", 30), ("User C", 40)]
2711+
2712+
def test_order_by_using_raw_and_keys_raises_exception(self):
2713+
with pytest.raises(OperationError):
2714+
self.Person.objects.order_by("-name", __raw__=[("age", pymongo.ASCENDING)])
2715+
26832716
def test_confirm_order_by_reference_wont_work(self):
26842717
"""Ordering by reference is not possible. Use map / reduce.. or
26852718
denormalise"""

0 commit comments

Comments
 (0)