Fixes saving document schemas that have changed

Ensures that form defaults which are documents are
automatically marked as changed, so schemas can evolve
without migration issues.

[#360]
This commit is contained in:
Ross Lawley 2011-11-22 07:34:08 -08:00
parent 34646a414c
commit 63c5a4dd65
4 changed files with 40 additions and 1 deletions

View File

@ -74,4 +74,5 @@ that much better:
* Marc Tamlyn * Marc Tamlyn
* Karim Allah * Karim Allah
* Adam Parrish * Adam Parrish
* jpfarias

View File

@ -5,6 +5,7 @@ Changelog
Changes in dev Changes in dev
============== ==============
- Fixed document mutation saving issue
- Fixed positional operator when replacing embedded documents - Fixed positional operator when replacing embedded documents
- Added Non-Django Style choices back (you can have either) - Added Non-Django Style choices back (you can have either)
- Fixed __repr__ of a sliced queryset - Fixed __repr__ of a sliced queryset

View File

@ -883,14 +883,21 @@ class BaseDocument(object):
""".strip() % class_name) """.strip() % class_name)
cls = subclasses[class_name] cls = subclasses[class_name]
changed_fields = []
for field_name, field in cls._fields.items(): for field_name, field in cls._fields.items():
if field.db_field in data: if field.db_field in data:
value = data[field.db_field] value = data[field.db_field]
data[field_name] = (value if value is None data[field_name] = (value if value is None
else field.to_python(value)) else field.to_python(value))
elif field.default:
default = field.default
if callable(default):
default = default()
if isinstance(default, BaseDocument):
changed_fields.append(field_name)
obj = cls(**data) obj = cls(**data)
obj._changed_fields = [] obj._changed_fields = changed_fields
return obj return obj
def _mark_as_changed(self, key): def _mark_as_changed(self, key):

View File

@ -2360,6 +2360,36 @@ class DocumentTest(unittest.TestCase):
self.assertRaises(InvalidDocumentError, throw_invalid_document_error) self.assertRaises(InvalidDocumentError, throw_invalid_document_error)
def test_mutating_documents(self):
class B(EmbeddedDocument):
field1 = StringField(default='field1')
class A(Document):
b = EmbeddedDocumentField(B, default=lambda: B())
A.drop_collection()
a = A()
a.save()
a.reload()
self.assertEquals(a.b.field1, 'field1')
class C(EmbeddedDocument):
c_field = StringField(default='cfield')
class B(EmbeddedDocument):
field1 = StringField(default='field1')
field2 = EmbeddedDocumentField(C, default=lambda: C())
class A(Document):
b = EmbeddedDocumentField(B, default=lambda: B())
a = A.objects()[0]
a.b.field2.c_field = 'new value'
a.save()
a.reload()
self.assertEquals(a.b.field2.c_field, 'new value')
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()