Skip to content

Update of a ListField depends on an unrelated dynamic field update #1733

@th-erker

Description

@th-erker

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] = 1

However, 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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions