Skip to content

Commit 9050869

Browse files
author
Omer Katz
committed
Merge pull request #1042 from closeio/fix-read-preference
Fix read_preference
2 parents 6868f66 + 54975de commit 9050869

File tree

3 files changed

+59
-3
lines changed

3 files changed

+59
-3
lines changed

docs/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Changes in 0.10.2
77
- Allow shard key to point to a field in an embedded document. #551
88
- Allow arbirary metadata in fields. #1129
99
- ReferenceFields now support abstract document types. #837
10+
- Fix `read_preference` (it had chaining issues with PyMongo 2.x and it didn't work at all with PyMongo 3.x) #1042
1011

1112
Changes in 0.10.1
1213
=======================

mongoengine/queryset/base.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,7 @@ def read_preference(self, read_preference):
930930
validate_read_preference('read_preference', read_preference)
931931
queryset = self.clone()
932932
queryset._read_preference = read_preference
933+
queryset._cursor_obj = None # we need to re-create the cursor object whenever we apply read_preference
933934
return queryset
934935

935936
def scalar(self, *fields):
@@ -1443,8 +1444,16 @@ def _cursor_args(self):
14431444
def _cursor(self):
14441445
if self._cursor_obj is None:
14451446

1446-
self._cursor_obj = self._collection.find(self._query,
1447-
**self._cursor_args)
1447+
# In PyMongo 3+, we define the read preference on a collection
1448+
# level, not a cursor level. Thus, we need to get a cloned
1449+
# collection object using `with_options` first.
1450+
if IS_PYMONGO_3 and self._read_preference is not None:
1451+
self._cursor_obj = self._collection\
1452+
.with_options(read_preference=self._read_preference)\
1453+
.find(self._query, **self._cursor_args)
1454+
else:
1455+
self._cursor_obj = self._collection.find(self._query,
1456+
**self._cursor_args)
14481457
# Apply where clauses to cursor
14491458
if self._where_clause:
14501459
where_clause = self._sub_js_fields(self._where_clause)

tests/queryset/queryset.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4165,7 +4165,11 @@ class MyDoc(Document):
41654165

41664166
def test_read_preference(self):
41674167
class Bar(Document):
4168-
pass
4168+
txt = StringField()
4169+
4170+
meta = {
4171+
'indexes': [ 'txt' ]
4172+
}
41694173

41704174
Bar.drop_collection()
41714175
bars = list(Bar.objects(read_preference=ReadPreference.PRIMARY))
@@ -4177,9 +4181,51 @@ class Bar(Document):
41774181
error_class = TypeError
41784182
self.assertRaises(error_class, Bar.objects, read_preference='Primary')
41794183

4184+
# read_preference as a kwarg
41804185
bars = Bar.objects(read_preference=ReadPreference.SECONDARY_PREFERRED)
41814186
self.assertEqual(
41824187
bars._read_preference, ReadPreference.SECONDARY_PREFERRED)
4188+
self.assertEqual(bars._cursor._Cursor__read_preference,
4189+
ReadPreference.SECONDARY_PREFERRED)
4190+
4191+
# read_preference as a query set method
4192+
bars = Bar.objects.read_preference(ReadPreference.SECONDARY_PREFERRED)
4193+
self.assertEqual(
4194+
bars._read_preference, ReadPreference.SECONDARY_PREFERRED)
4195+
self.assertEqual(bars._cursor._Cursor__read_preference,
4196+
ReadPreference.SECONDARY_PREFERRED)
4197+
4198+
# read_preference after skip
4199+
bars = Bar.objects.skip(1) \
4200+
.read_preference(ReadPreference.SECONDARY_PREFERRED)
4201+
self.assertEqual(
4202+
bars._read_preference, ReadPreference.SECONDARY_PREFERRED)
4203+
self.assertEqual(bars._cursor._Cursor__read_preference,
4204+
ReadPreference.SECONDARY_PREFERRED)
4205+
4206+
# read_preference after limit
4207+
bars = Bar.objects.limit(1) \
4208+
.read_preference(ReadPreference.SECONDARY_PREFERRED)
4209+
self.assertEqual(
4210+
bars._read_preference, ReadPreference.SECONDARY_PREFERRED)
4211+
self.assertEqual(bars._cursor._Cursor__read_preference,
4212+
ReadPreference.SECONDARY_PREFERRED)
4213+
4214+
# read_preference after order_by
4215+
bars = Bar.objects.order_by('txt') \
4216+
.read_preference(ReadPreference.SECONDARY_PREFERRED)
4217+
self.assertEqual(
4218+
bars._read_preference, ReadPreference.SECONDARY_PREFERRED)
4219+
self.assertEqual(bars._cursor._Cursor__read_preference,
4220+
ReadPreference.SECONDARY_PREFERRED)
4221+
4222+
# read_preference after hint
4223+
bars = Bar.objects.hint([('txt', 1)]) \
4224+
.read_preference(ReadPreference.SECONDARY_PREFERRED)
4225+
self.assertEqual(
4226+
bars._read_preference, ReadPreference.SECONDARY_PREFERRED)
4227+
self.assertEqual(bars._cursor._Cursor__read_preference,
4228+
ReadPreference.SECONDARY_PREFERRED)
41834229

41844230
def test_json_simple(self):
41854231

0 commit comments

Comments
 (0)