Compare commits

...

3 Commits

Author SHA1 Message Date
Stefan Wojcik
a52d3b92a8 fix BaseQuerySet.fields when mixing exclusion/inclusion with complex values like $slice 2016-12-28 11:06:14 -05:00
Stefan Wójcik
f4e1d80a87 support a negative dec operator (#1450) 2016-12-28 02:04:49 -05:00
Stefan Wójcik
91dad4060f raise an error when trying to save an abstract document (#1449) 2016-12-28 00:51:47 -05:00
6 changed files with 42 additions and 4 deletions

View File

@@ -313,6 +313,9 @@ class Document(BaseDocument):
.. versionchanged:: 0.10.7 .. versionchanged:: 0.10.7
Add signal_kwargs argument Add signal_kwargs argument
""" """
if self._meta.get('abstract'):
raise InvalidDocumentError('Cannot save an abstract document.')
signal_kwargs = signal_kwargs or {} signal_kwargs = signal_kwargs or {}
signals.pre_save.send(self.__class__, document=self, **signal_kwargs) signals.pre_save.send(self.__class__, document=self, **signal_kwargs)
@@ -828,7 +831,6 @@ class Document(BaseDocument):
""" Lists all of the indexes that should be created for given """ Lists all of the indexes that should be created for given
collection. It includes all the indexes from super- and sub-classes. collection. It includes all the indexes from super- and sub-classes.
""" """
if cls._meta.get('abstract'): if cls._meta.get('abstract'):
return [] return []

View File

@@ -933,7 +933,20 @@ class BaseQuerySet(object):
key = '.'.join(parts) key = '.'.join(parts)
cleaned_fields.append((key, value)) 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() queryset = self.clone()
for value, group in itertools.groupby(fields, lambda x: x[1]): for value, group in itertools.groupby(fields, lambda x: x[1]):
fields = [field for field, value in group] fields = [field for field, value in group]

View File

@@ -233,8 +233,7 @@ def update(_doc_cls=None, **update):
# Support decrement by flipping a positive value's sign # Support decrement by flipping a positive value's sign
# and using 'inc' # and using 'inc'
op = 'inc' op = 'inc'
if value > 0: value = -value
value = -value
elif op == 'add_to_set': elif op == 'add_to_set':
op = 'addToSet' op = 'addToSet'
elif op == 'set_on_insert': elif op == 'set_on_insert':

View File

@@ -435,6 +435,15 @@ class InstanceTest(unittest.TestCase):
person.to_dbref() person.to_dbref()
def test_save_abstract_document(self):
"""Saving an abstract document should fail."""
class Doc(Document):
name = StringField()
meta = {'abstract': True}
with self.assertRaises(InvalidDocumentError):
Doc(name='aaa').save()
def test_reload(self): def test_reload(self):
"""Ensure that attributes may be reloaded. """Ensure that attributes may be reloaded.
""" """

View File

@@ -141,6 +141,16 @@ class OnlyExcludeAllTest(unittest.TestCase):
self.assertEqual(qs._loaded_fields.as_dict(), self.assertEqual(qs._loaded_fields.as_dict(),
{'b': {'$slice': 5}}) {'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): def test_only(self):
"""Ensure that QuerySet.only only returns the requested fields. """Ensure that QuerySet.only only returns the requested fields.
""" """

View File

@@ -1826,6 +1826,11 @@ class QuerySetTest(unittest.TestCase):
post.reload() post.reload()
self.assertEqual(post.hits, 10) self.assertEqual(post.hits, 10)
# Negative dec operator is equal to a positive inc operator
BlogPost.objects.update_one(dec__hits=-1)
post.reload()
self.assertEqual(post.hits, 11)
BlogPost.objects.update(push__tags='mongo') BlogPost.objects.update(push__tags='mongo')
post.reload() post.reload()
self.assertTrue('mongo' in post.tags) self.assertTrue('mongo' in post.tags)