diff --git a/mongoengine/fields.py b/mongoengine/fields.py index 4695bf81..4c739d95 100644 --- a/mongoengine/fields.py +++ b/mongoengine/fields.py @@ -155,6 +155,29 @@ class ListField(BaseField): self.field = field super(ListField, self).__init__(**kwargs) + def __get__(self, instance, owner): + """Descriptor to automatically dereference references. + """ + if instance is None: + # Document class being used rather than a document object + return self + + if isinstance(self.field, ReferenceField): + referenced_type = self.field.document_type + # Get value from document instance if available + value_list = instance._data.get(self.name) + deref_list = [] + for value in value_list: + # Dereference DBRefs + if isinstance(value, (pymongo.dbref.DBRef)): + value = _get_db().dereference(value) + deref_list.append(referenced_type._from_son(value)) + else: + deref_list.append(value) + instance._data[self.name] = deref_list + + return super(ListField, self).__get__(instance, owner) + def to_python(self, value): return [self.field.to_python(item) for item in value] diff --git a/tests/fields.py b/tests/fields.py index b35a9142..6eee972e 100644 --- a/tests/fields.py +++ b/tests/fields.py @@ -285,6 +285,34 @@ class FieldTest(unittest.TestCase): User.drop_collection() BlogPost.drop_collection() + + def test_list_item_dereference(self): + """Ensure that DBRef items in ListFields are dereferenced. + """ + class User(Document): + name = StringField() + + class Group(Document): + members = ListField(ReferenceField(User)) + + User.drop_collection() + Group.drop_collection() + + user1 = User(name='user1') + user1.save() + user2 = User(name='user2') + user2.save() + + group = Group(members=[user1, user2]) + group.save() + + group_obj = Group.objects.first() + + self.assertEqual(group_obj.members[0].name, user1.name) + self.assertEqual(group_obj.members[1].name, user2.name) + + User.drop_collection() + Group.drop_collection() def test_reference_query_conversion(self): """Ensure that ReferenceFields can be queried using objects and values