mongoengine icon indicating copy to clipboard operation
mongoengine copied to clipboard

.append() to a ListField(ReferenceField()) silently fails under specific circumstances

Open djziegler opened this issue 14 years ago • 2 comments


"""
Demonstrate a somewhat obscure bug with ListField(ReferenceField()).

1) Create an object with an empty ListField(ReferenceField()).
   - the field can either be left empty (using the default value),
     or you can explicity set it to empty.
   - issue does not occur with ListField(StringField())
   - if an object is appended now (before first persist) problem does not occur.
2) Save the object and reload it.
3) Append an entity to the ListField(ReferenceField()).
   - the object will be silently dropped.
   - setting the field to a list containing the item is a workaround.
   - if an object had been added to the list in step 1, adding the
     second object now would be fine.
"""

from mongoengine import *
import sys

class Dog(Document):
    name = StringField ()
    puppies = ListField(ReferenceField('Dog'))

def test ():

    connect ('testdb')

    Dog.drop_collection ()

    # Create dog with empty puppies list
    rover0 = Dog (name='Rover')

    # Turning this on does not fix the problem
    if False: 
        rover0.puppies = []

    # If you turn this on, both this case, and the after-reload case will work fine.
    if False:
        puppy0 = Dog (name='puppy0')
        puppy0.save ()
        rover0.puppies.append (puppy0)
        print 'Added a puppy before initial save', [p.name for p in rover0.puppies]

    # Save the dog
    rover0.save ()

    # Load the same dog again
    rover1 = Dog.objects(name='Rover').get ()

    # Create and persist a puppy
    puppy1 = Dog (name='puppy1')
    puppy1.save ()

    # Turning this on does not fix the problem
    if False: 
        rover1.puppies = []

    # Append the puppy to the puppies list
    rover1.puppies.append (puppy1)
    if puppy1 not in rover1.puppies:
        print '*** Whoops: puppy did not get appended:', [p.name for p in rover1.puppies]

    # This works however
    rover1.puppies = rover1.puppies + [puppy1]
    print 'Using workaround, all is good:', [p.name for p in rover1.puppies]

if __name__ == '__main__':
    test ()

djziegler avatar Jan 05 '12 16:01 djziegler

@djziegler thanks for the excellent bug report - looking into it!

rozza avatar Jan 08 '12 15:01 rozza

I have (approximately) the same issue, and it took me a long time to find this old bug report. In my case I don't even load the object again. I save it, then try to add an item, and save it again. This silently fails. Is this bug fixed in version 0.9 or taken into account?

arthursw avatar Jan 22 '15 15:01 arthursw