diff --git a/docs/changelog.rst b/docs/changelog.rst index c1019375..3e93fc91 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,7 @@ Changelog Changes in 0.6.X ================ +- Added support for pull operations on nested EmbeddedDocuments - Added support for choices with GenericReferenceFields - Added support for choices with GenericEmbeddedDocumentFields - Fixed Django 1.4 sessions first save data loss diff --git a/mongoengine/queryset.py b/mongoengine/queryset.py index e3f83c78..6d8cc7a5 100644 --- a/mongoengine/queryset.py +++ b/mongoengine/queryset.py @@ -1380,9 +1380,18 @@ class QuerySet(object): if not op: raise InvalidQueryError("Updates must supply an operation eg: set__FIELD=value") - if op: + if 'pull' in op and '.' in key: + # Dot operators don't work on pull operations + # it uses nested dict syntax + if op == 'pullAll': + raise InvalidQueryError("pullAll operations only support a single field depth") + + parts.reverse() + for key in parts: + value = {key: value} + else: value = {key: value} - key = '$' + op + key = '$' + op if key not in mongo_update: mongo_update[key] = value diff --git a/tests/queryset.py b/tests/queryset.py index 4cf11657..3b662489 100644 --- a/tests/queryset.py +++ b/tests/queryset.py @@ -572,7 +572,7 @@ class QuerySetTest(unittest.TestCase): def throw_operation_error_not_unique(): Blog.objects.insert([blog2, blog3], safe=True) - + self.assertRaises(OperationError, throw_operation_error_not_unique) self.assertEqual(Blog.objects.count(), 2) @@ -1471,6 +1471,35 @@ class QuerySetTest(unittest.TestCase): post.reload() self.assertEqual(post.tags, ["code", "mongodb"]) + def test_pull_nested(self): + + class User(Document): + name = StringField() + + class Collaborator(EmbeddedDocument): + user = StringField() + + def __unicode__(self): + return '%s' % self.user + + class Site(Document): + name = StringField(max_length=75, unique=True, required=True) + collaborators = ListField(EmbeddedDocumentField(Collaborator)) + + + Site.drop_collection() + + c = Collaborator(user='Esteban') + s = Site(name="test", collaborators=[c]) + s.save() + + Site.objects(id=s.id).update_one(pull__collaborators__user='Esteban') + self.assertEqual(Site.objects.first().collaborators, []) + + def pull_all(): + Site.objects(id=s.id).update_one(pull_all__collaborators__user=['Ross']) + + self.assertRaises(InvalidQueryError, pull_all) def test_update_one_pop_generic_reference(self):