Skip to content

Commit 365c8b3

Browse files
authored
Merge pull request #2735 from bagerard/jaesivsm__mark-dict-field-as-dirty
CLONE - (Jaesivsm) mark dict field as dirty
2 parents 4df0f8f + bcf0245 commit 365c8b3

File tree

3 files changed

+48
-4
lines changed

3 files changed

+48
-4
lines changed

docs/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Development
1111
Typically to support mock mongo libraries like mongomock, montydb, mongita #2729
1212
- BREAKING CHANGE: connecting MongoEngine with mongomock should now use the new `mongo_client_class`
1313
For more info, check https://docs.mongoengine.org/guide/mongomock.html
14+
- Fix DictField that always gets marked as changed #2606
1415

1516
Changes in 0.26.0
1617
=================

mongoengine/base/datastructures.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ def mark_key_as_changed_wrapper(parent_method):
3131

3232
def wrapper(self, key, *args, **kwargs):
3333
# Can't use super() in the decorator.
34-
result = parent_method(self, key, *args, **kwargs)
35-
self._mark_as_changed(key)
36-
return result
34+
if not args or not key or key not in self or self[key] != args[0]:
35+
self._mark_as_changed(key)
36+
return parent_method(self, key, *args, **kwargs)
3737

3838
return wrapper
3939

tests/document/test_delta.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from mongoengine import *
66
from mongoengine.pymongo_support import list_collection_names
7-
from tests.utils import MongoDBTestCase
7+
from tests.utils import MongoDBTestCase, get_as_pymongo
88

99

1010
class TestDelta(MongoDBTestCase):
@@ -952,6 +952,49 @@ class Doc(Document):
952952
assert "oops" == delta[0]["users.007.rolist"][0]["type"]
953953
assert uinfo.id == delta[0]["users.007.info"]
954954

955+
def test_delta_on_dict(self):
956+
class MyDoc(Document):
957+
dico = DictField()
958+
959+
MyDoc.drop_collection()
960+
961+
MyDoc(dico={"a": {"b": 0}}).save()
962+
963+
mydoc = MyDoc.objects.first()
964+
assert mydoc._get_changed_fields() == []
965+
mydoc.dico["a"]["b"] = 0
966+
assert mydoc._get_changed_fields() == []
967+
mydoc.dico["a"] = {"b": 0}
968+
assert mydoc._get_changed_fields() == []
969+
mydoc.dico = {"a": {"b": 0}}
970+
assert mydoc._get_changed_fields() == []
971+
mydoc.dico["a"]["c"] = 1
972+
assert mydoc._get_changed_fields() == ["dico.a.c"]
973+
mydoc.dico["a"]["b"] = 2
974+
mydoc.dico["d"] = 3
975+
assert mydoc._get_changed_fields() == ["dico.a.c", "dico.a.b", "dico.d"]
976+
977+
mydoc._clear_changed_fields()
978+
assert mydoc._get_changed_fields() == []
979+
980+
def test_delta_on_dict_empty_key_triggers_full_change(self):
981+
"""more of a bug (harmless) but empty key changes aren't managed perfectly"""
982+
983+
class MyDoc(Document):
984+
dico = DictField()
985+
986+
MyDoc.drop_collection()
987+
988+
MyDoc(dico={"a": {"b": 0}}).save()
989+
990+
mydoc = MyDoc.objects.first()
991+
assert mydoc._get_changed_fields() == []
992+
mydoc.dico[""] = 3
993+
assert mydoc._get_changed_fields() == ["dico"]
994+
mydoc.save()
995+
raw_doc = get_as_pymongo(mydoc)
996+
assert raw_doc == {"_id": mydoc.id, "dico": {"": 3, "a": {"b": 0}}}
997+
955998

956999
if __name__ == "__main__":
9571000
unittest.main()

0 commit comments

Comments
 (0)