Skip to content

Slicing a ListField(EmbeddedField) can lead to strange value in _changed_fields #1855

@bagerard

Description

@bagerard

While fixing something else in BaseList, I noticed that slicing a BaseList could lead to bad values of the parent document._changed_fields. Additionally, it is behaving differently under python2 and python3.

In fact, see below (under PY3):

class Age(me.EmbeddedDocument):
    age = me.IntField()

class Person(me.Document):
    ages = me.EmbeddedDocumentListField(Age)

p = Person()
p.ages = [Age(age=1), Age(age=2), Age(age=3)]
p.save()

sliced = p.ages[1:3]
print(sliced)			# [<Age: Age object>, <Age: Age object>]
print(type(sliced))		# <class 'mongoengine.base.datastructures.BaseList'>
print(sliced._instance) 	# Person object
print(sliced._name)		# "ages.slice(1, 3, None)" <---- BOOM!
print(p._changed_fields)	# []
sliced[1] = Age(age=1000)
print(p._changed_fields)	# ['ages.slice(1, 3, None).1'] >
p.save()			# Fails with OperationError: Could not save document (cannot use the part (ages of ages.slice(1, 3, None).1)...

Under PY2, here is the output:

class Age(me.EmbeddedDocument):
    age = me.IntField()

class Person(me.Document):
    ages = me.EmbeddedDocumentListField(Age)


p = Person()
p.ages = [Age(age=1), Age(age=2), Age(age=3)]
p.save()

sliced = p.ages[1:3]
print(sliced)			# [<Age: Age object>, <Age: Age object>]
print(type(sliced))		# list (and not a BaseList like in PY3)
print(sliced._instance)		# Fails with AttributeError: 'list' object has no attribute '_instance'

The difference between PY2 & PY3 comes from the fact that PY2 calls BaseList.getslice and PY3 calls getitem (with key being a slice, which causes the weird ._name attribute). This is something I'm harmonizing in another PR (#1853) so that at least it will behave the same (but faulty).

Being able to track changes properly after slicing is not trivial, especially if we try to identify specifically the index/key of the things being changed. I'll think of it in the next days, if I manage to find a clean fix, I'll push a PR

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