From 0338ac17b1be78050e82e1222a84c805b870bf9c Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Wed, 15 Jun 2011 08:55:31 +0100 Subject: [PATCH] Fixes multiple assignment issue preventing saves Thanks to @wpjunior for the ticket and testcase Also fixed bug in BaseList fixes #195 --- mongoengine/base.py | 6 +++--- tests/document.py | 39 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/mongoengine/base.py b/mongoengine/base.py index c5b704e1..1ca1680a 100644 --- a/mongoengine/base.py +++ b/mongoengine/base.py @@ -784,9 +784,9 @@ class BaseDocument(object): for field_name in self._fields: key = '%s.' % field_name field = getattr(self, field_name, None) - if isinstance(field, EmbeddedDocument): # Grab all embedded fields that have been changed + if isinstance(field, EmbeddedDocument) and field_name not in _changed_fields: # Grab all embedded fields that have been changed _changed_fields += ["%s%s" % (key, k) for k in field._get_changed_fields(key) if k] - elif isinstance(field, (list, tuple)): # Loop list fields as they contain documents + elif isinstance(field, (list, tuple)) and field_name not in _changed_fields: # Loop list fields as they contain documents for index, value in enumerate(field): if not hasattr(value, '_get_changed_fields'): continue @@ -858,7 +858,7 @@ class BaseList(list): def __setitem__(self, *args, **kwargs): if hasattr(self, 'instance') and hasattr(self, 'name'): self.instance._mark_as_changed(self.name) - super(BaseDict, self).__setitem__(*args, **kwargs) + super(BaseList, self).__setitem__(*args, **kwargs) def __delitem__(self, *args, **kwargs): self.instance._mark_as_changed(self.name) diff --git a/tests/document.py b/tests/document.py index 4c890800..4f90ba2d 100644 --- a/tests/document.py +++ b/tests/document.py @@ -933,31 +933,35 @@ class DocumentTest(unittest.TestCase): self.assertEquals(doc._delta(), ({}, {})) doc.string_field = 'hello' + self.assertEquals(doc._get_changed_fields(), ['string_field']) self.assertEquals(doc._delta(), ({'string_field': 'hello'}, {})) doc._changed_fields = [] doc.int_field = 1 + self.assertEquals(doc._get_changed_fields(), ['int_field']) self.assertEquals(doc._delta(), ({'int_field': 1}, {})) doc._changed_fields = [] dict_value = {'hello': 'world', 'ping': 'pong'} doc.dict_field = dict_value + self.assertEquals(doc._get_changed_fields(), ['dict_field']) self.assertEquals(doc._delta(), ({'dict_field': dict_value}, {})) doc._changed_fields = [] list_value = ['1', 2, {'hello': 'world'}] doc.list_field = list_value + self.assertEquals(doc._get_changed_fields(), ['list_field']) self.assertEquals(doc._delta(), ({'list_field': list_value}, {})) # Test unsetting doc._changed_fields = [] - doc._unset_fields = [] doc.dict_field = {} + self.assertEquals(doc._get_changed_fields(), ['dict_field']) self.assertEquals(doc._delta(), ({}, {'dict_field': 1})) doc._changed_fields = [] - doc._unset_fields = {} doc.list_field = [] + self.assertEquals(doc._get_changed_fields(), ['list_field']) self.assertEquals(doc._delta(), ({}, {'list_field': 1})) def test_delta_recursive(self): @@ -990,6 +994,8 @@ class DocumentTest(unittest.TestCase): embedded_1.list_field = ['1', 2, {'hello': 'world'}] doc.embedded_field = embedded_1 + self.assertEquals(doc._get_changed_fields(), ['embedded_field']) + embedded_delta = { '_types': ['Embedded'], '_cls': 'Embedded', @@ -1005,6 +1011,7 @@ class DocumentTest(unittest.TestCase): doc.reload() doc.embedded_field.dict_field = {} + self.assertEquals(doc._get_changed_fields(), ['embedded_field.dict_field']) self.assertEquals(doc.embedded_field._delta(), ({}, {'dict_field': 1})) self.assertEquals(doc._delta(), ({}, {'embedded_field.dict_field': 1})) doc.save() @@ -1012,6 +1019,7 @@ class DocumentTest(unittest.TestCase): self.assertEquals(doc.embedded_field.dict_field, {}) doc.embedded_field.list_field = [] + self.assertEquals(doc._get_changed_fields(), ['embedded_field.list_field']) self.assertEquals(doc.embedded_field._delta(), ({}, {'list_field': 1})) self.assertEquals(doc._delta(), ({}, {'embedded_field.list_field': 1})) doc.save() @@ -1025,6 +1033,7 @@ class DocumentTest(unittest.TestCase): embedded_2.list_field = ['1', 2, {'hello': 'world'}] doc.embedded_field.list_field = ['1', 2, embedded_2] + self.assertEquals(doc._get_changed_fields(), ['embedded_field.list_field']) self.assertEquals(doc.embedded_field._delta(), ({ 'list_field': ['1', 2, { '_cls': 'Embedded', @@ -1055,12 +1064,38 @@ class DocumentTest(unittest.TestCase): self.assertEquals(doc.embedded_field.list_field[2][k], embedded_2[k]) doc.embedded_field.list_field[2].string_field = 'world' + self.assertEquals(doc._get_changed_fields(), ['embedded_field.list_field.2.string_field']) self.assertEquals(doc.embedded_field._delta(), ({'list_field.2.string_field': 'world'}, {})) self.assertEquals(doc._delta(), ({'embedded_field.list_field.2.string_field': 'world'}, {})) doc.save() doc.reload() self.assertEquals(doc.embedded_field.list_field[2].string_field, 'world') + # Test multiple assignments + doc.embedded_field.list_field[2].string_field = 'hello world' + doc.embedded_field.list_field[2] = doc.embedded_field.list_field[2] + self.assertEquals(doc._get_changed_fields(), ['embedded_field.list_field']) + self.assertEquals(doc.embedded_field._delta(), ({ + 'list_field': ['1', 2, { + '_types': ['Embedded'], + '_cls': 'Embedded', + 'string_field': 'hello world', + 'int_field': 1, + 'list_field': ['1', 2, {'hello': 'world'}], + 'dict_field': {'hello': 'world'}}]}, {})) + self.assertEquals(doc._delta(), ({ + 'embedded_field.list_field': ['1', 2, { + '_types': ['Embedded'], + '_cls': 'Embedded', + 'string_field': 'hello world', + 'int_field': 1, + 'list_field': ['1', 2, {'hello': 'world'}], + 'dict_field': {'hello': 'world'}} + ]}, {})) + doc.save() + doc.reload() + self.assertEquals(doc.embedded_field.list_field[2].string_field, 'hello world') + # Test list native methods doc.embedded_field.list_field[2].list_field.pop(0) self.assertEquals(doc._delta(), ({'embedded_field.list_field.2.list_field': [2, {'hello': 'world'}]}, {}))