I have an issue with the updating of a DictField of a DynamicDocument that sometimes raises an exception.
It seems that there is a bug in mongoengine (more precisely in the _changed_fields) when we try to update a key of an inner dict, within the DictField that is at the top level of the Document.
As far as I dug, it seems to be because the inner dict is considered as a BaseDict, so when it is updated, the inner dict is added to _changed_fields but this inner dict isn't a field of the document, so there is an AttributeError on save() (see traceback below).
One more thing: this seem to be the case only with DynamicDocument and not with Document. And there is also no exception raised when the document came from the database.
Tested on versions:
Python 3.10.13
MongoEngine 0.27.0
PyMongo 4.6.1
Code to reproduce the bug:
from mongoengine import connect, DictField, DynamicDocument
connect("test", host="mongodb://localhost:27018/test")
class ExampleModel(DynamicDocument): # but there is no exception at all with `Document`
root_dict = DictField(default=None)
ExampleModel.objects().delete() # just in case
example = ExampleModel()
example.root_dict = {"inner_dict":{"key": "value"}}
example.save() # ✅
if example.root_dict["inner_dict"]["key"]:
print("'inner_dict' is present in 'example'")
# ------------------
# example.reload() # <-- with this line uncommented, no exception is raised
example.root_dict["inner_dict"]["key"] = "NEW_value"
try:
example.save() # raise "AttributeError" ❌
except AttributeError as exc:
print(exc)
else:
print("No exception for 'example'")
# ------------------
example_from_db = ExampleModel.objects().first()
example_from_db.root_dict["inner_dict"]["key"] = "NEW_value"
try:
example_from_db.save() # don't raise any exception ✅
except AttributeError as exc:
print(exc)
else:
print("No exception for 'example_from_db'")
Output of this program:
'inner_dict' is present in 'example'
'ExampleModel' object has no attribute 'inner_dict'
No exception for 'example_from_db'
Complete traceback of the error on .save():
Traceback (most recent call last):
File "/workspaces/bin/personal/mongoengine_dictfield.py", line 23, in <module>
example.save()
File "/workspaces/.venv/lib/python3.10/site-packages/mongoengine/document.py", line 429, in save
object_id, created = self._save_update(
File "/workspaces/.venv/lib/python3.10/site-packages/mongoengine/document.py", line 545, in _save_update
update_doc = self._get_update_doc()
File "/workspaces/.venv/lib/python3.10/site-packages/mongoengine/document.py", line 501, in _get_update_doc
updates, removals = self._delta()
File "/workspaces/.venv/lib/python3.10/site-packages/mongoengine/base/document.py", line 746, in _delta
d = getattr(d, real_path)
AttributeError: 'ExampleModel' object has no attribute 'inner_dict'
Hi,
Details:
I have an issue with the updating of a
DictField
of aDynamicDocument
that sometimes raises an exception. It seems that there is a bug inmongoengine
(more precisely in the_changed_fields
) when we try to update a key of an inner dict, within the DictField that is at the top level of theDocument
. As far as I dug, it seems to be because the inner dict is considered as aBaseDict
, so when it is updated, the inner dict is added to_changed_fields
but this inner dict isn't a field of the document, so there is anAttributeError
onsave()
(see traceback below).One more thing: this seem to be the case only with
DynamicDocument
and not withDocument
. And there is also no exception raised when the document came from the database.Tested on versions:
3.10.13
0.27.0
4.6.1
Code to reproduce the bug:
Output of this program:
Complete traceback of the error on
.save()
: