From a52d3b92a86ea7d51cd04053692d549de0461ba5 Mon Sep 17 00:00:00 2001 From: Stefan Wojcik Date: Wed, 28 Dec 2016 11:06:14 -0500 Subject: [PATCH] fix BaseQuerySet.fields when mixing exclusion/inclusion with complex values like $slice --- mongoengine/queryset/base.py | 15 ++++++++++++++- tests/queryset/field_list.py | 10 ++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/mongoengine/queryset/base.py b/mongoengine/queryset/base.py index 5c0fb5b3..098f198e 100644 --- a/mongoengine/queryset/base.py +++ b/mongoengine/queryset/base.py @@ -933,7 +933,20 @@ class BaseQuerySet(object): key = '.'.join(parts) cleaned_fields.append((key, value)) - fields = sorted(cleaned_fields, key=operator.itemgetter(1)) + # Sort fields by their values, explicitly excluded fields first, then + # explicitly included, and then more complicated operators such as + # $slice. + def _sort_key(field_tuple): + key, value = field_tuple + if isinstance(value, (int)): + return value # 0 for exclusion, 1 for inclusion + else: + return 2 # so that complex values appear last + + fields = sorted(cleaned_fields, key=_sort_key) + + # Clone the queryset, group all fields by their value, convert + # each of them to db_fields, and set the queryset's _loaded_fields queryset = self.clone() for value, group in itertools.groupby(fields, lambda x: x[1]): fields = [field for field, value in group] diff --git a/tests/queryset/field_list.py b/tests/queryset/field_list.py index 76d5f779..d1277e06 100644 --- a/tests/queryset/field_list.py +++ b/tests/queryset/field_list.py @@ -141,6 +141,16 @@ class OnlyExcludeAllTest(unittest.TestCase): self.assertEqual(qs._loaded_fields.as_dict(), {'b': {'$slice': 5}}) + def test_mix_slice_with_other_fields(self): + class MyDoc(Document): + a = ListField() + b = ListField() + c = ListField() + + qs = MyDoc.objects.fields(a=1, b=0, slice__c=2) + self.assertEqual(qs._loaded_fields.as_dict(), + {'c': {'$slice': 2}, 'a': 1}) + def test_only(self): """Ensure that QuerySet.only only returns the requested fields. """