Skip to content

Commit abc3fc3

Browse files
authored
Merge pull request #2789 from bagerard/add_raw__order_by
add __raw__ to order_by
2 parents 5c5a724 + 9068d1a commit abc3fc3

File tree

4 files changed

+52
-3
lines changed

4 files changed

+52
-3
lines changed

docs/changelog.rst

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

2122
Changes in 0.27.0
2223
=================

mongoengine/context_managers.py

+1
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

+11-3
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

+39
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
MONGODB_36,
1818
get_mongodb_version,
1919
)
20+
from mongoengine.pymongo_support import PYMONGO_VERSION
2021
from mongoengine.queryset import (
2122
DoesNotExist,
2223
MultipleObjectsReturned,
@@ -2720,6 +2721,44 @@ def test_order_by_chaining(self):
27202721
ages = [p.age for p in qs]
27212722
assert ages == [40, 30, 20]
27222723

2724+
def test_order_by_using_raw(self):
2725+
person_a = self.Person(name="User A", age=20)
2726+
person_a.save()
2727+
person_b = self.Person(name="User B", age=30)
2728+
person_b.save()
2729+
person_c = self.Person(name="User B", age=25)
2730+
person_c.save()
2731+
person_d = self.Person(name="User C", age=40)
2732+
person_d.save()
2733+
2734+
qs = self.Person.objects.order_by(__raw__=[("name", pymongo.DESCENDING)])
2735+
assert qs._ordering == [("name", pymongo.DESCENDING)]
2736+
names = [p.name for p in qs]
2737+
assert names == ["User C", "User B", "User B", "User A"]
2738+
2739+
names = [
2740+
(p.name, p.age)
2741+
for p in self.Person.objects.order_by(__raw__=[("name", pymongo.ASCENDING)])
2742+
]
2743+
assert names == [("User A", 20), ("User B", 30), ("User B", 25), ("User C", 40)]
2744+
2745+
if PYMONGO_VERSION >= (4, 4):
2746+
# Pymongo >= 4.4 allow to mix single key with tuples inside the list
2747+
qs = self.Person.objects.order_by(
2748+
__raw__=["name", ("age", pymongo.ASCENDING)]
2749+
)
2750+
names = [(p.name, p.age) for p in qs]
2751+
assert names == [
2752+
("User A", 20),
2753+
("User B", 25),
2754+
("User B", 30),
2755+
("User C", 40),
2756+
]
2757+
2758+
def test_order_by_using_raw_and_keys_raises_exception(self):
2759+
with pytest.raises(OperationError):
2760+
self.Person.objects.order_by("-name", __raw__=[("age", pymongo.ASCENDING)])
2761+
27232762
def test_confirm_order_by_reference_wont_work(self):
27242763
"""Ordering by reference is not possible. Use map / reduce.. or
27252764
denormalise"""

0 commit comments

Comments
 (0)