-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Closed
Labels
Description
Summary
When a ListField is updated to the empty list, the actual behavior (setting to the empty list or unsetting) is dependent on whether any dynamic (ad-hoc) field is updated too.
How to reproduce
>>> class Doc(mongoengine.DynamicDocument):
... x = mongoengine.ListField(mongoengine.BooleanField(), default=lambda: [True])
...
>>> f = Doc()
>>> f.save()
<Doc: Doc object>
>>> f.x = []
>>> f.save()
<Doc: Doc object>
>>> f = Doc.objects.get(id=f.id)
>>> f.x
[]
>>>
>>> g = Doc()
>>> g.save()
<Doc: Doc object>
>>> g.x = []
>>> g.y = 1
>>> g.save()
<Doc: Doc object>
>>> g = Doc.objects.get(id=g.id)
>>> g.x
[True]Analysis
base.document.BaseDocument._delta calculates which fields (paths) to unset (instead of setting to a value). The relevant loop uses the following shortcut, otherwise the value is checked against the default for that field:
if (self._dynamic and len(parts) and parts[0] in
self._dynamic_fields):
del set_data[path]
unset_data[path] = 1However, parts is a leftover from the previous loop. So whenever the document is dynamic and a dynamic field is updated, this condition is true, and the field is unset (case g; the default value for x is used). Otherwise, the field x is set to [], because it is not equal to the default value (case f).