Do not keep calling _dereference on values if it has already been dereferenced.
This commit is contained in:
parent
0744892244
commit
fdcaca42ae
1
AUTHORS
1
AUTHORS
@ -250,3 +250,4 @@ that much better:
|
|||||||
* Trevor Hall (https://github.com/tjhall13)
|
* Trevor Hall (https://github.com/tjhall13)
|
||||||
* Gleb Voropaev (https://github.com/buggyspace)
|
* Gleb Voropaev (https://github.com/buggyspace)
|
||||||
* Paulo Amaral (https://github.com/pauloAmaral)
|
* Paulo Amaral (https://github.com/pauloAmaral)
|
||||||
|
* Gaurav Dadhania (https://github.com/GVRV)
|
||||||
|
@ -17,6 +17,7 @@ Changes in 0.17.0
|
|||||||
- Fix InvalidStringData error when using modify on a BinaryField #1127
|
- Fix InvalidStringData error when using modify on a BinaryField #1127
|
||||||
- DEPRECATION: `EmbeddedDocument.save` & `.reload` are marked as deprecated and will be removed in a next version of mongoengine #1552
|
- DEPRECATION: `EmbeddedDocument.save` & `.reload` are marked as deprecated and will be removed in a next version of mongoengine #1552
|
||||||
- Fix test suite and CI to support MongoDB 3.4 #1445
|
- Fix test suite and CI to support MongoDB 3.4 #1445
|
||||||
|
- Fix reference fields querying the database on each access if value contains orphan DBRefs
|
||||||
|
|
||||||
=================
|
=================
|
||||||
Changes in 0.16.3
|
Changes in 0.16.3
|
||||||
|
@ -276,11 +276,16 @@ class ComplexBaseField(BaseField):
|
|||||||
|
|
||||||
_dereference = _import_class('DeReference')()
|
_dereference = _import_class('DeReference')()
|
||||||
|
|
||||||
if instance._initialised and dereference and instance._data.get(self.name):
|
if (instance._initialised and
|
||||||
|
dereference and
|
||||||
|
instance._data.get(self.name) and
|
||||||
|
not getattr(instance._data[self.name], '_dereferenced', False)):
|
||||||
instance._data[self.name] = _dereference(
|
instance._data[self.name] = _dereference(
|
||||||
instance._data.get(self.name), max_depth=1, instance=instance,
|
instance._data.get(self.name), max_depth=1, instance=instance,
|
||||||
name=self.name
|
name=self.name
|
||||||
)
|
)
|
||||||
|
if hasattr(instance._data[self.name], '_dereferenced'):
|
||||||
|
instance._data[self.name]._dereferenced = True
|
||||||
|
|
||||||
value = super(ComplexBaseField, self).__get__(instance, owner)
|
value = super(ComplexBaseField, self).__get__(instance, owner)
|
||||||
|
|
||||||
|
@ -105,6 +105,14 @@ class FieldTest(unittest.TestCase):
|
|||||||
|
|
||||||
[m for m in group_obj.members]
|
[m for m in group_obj.members]
|
||||||
self.assertEqual(q, 2)
|
self.assertEqual(q, 2)
|
||||||
|
self.assertTrue(group_obj._data['members']._dereferenced)
|
||||||
|
|
||||||
|
# verifies that no additional queries gets executed
|
||||||
|
# if we re-iterate over the ListField once it is
|
||||||
|
# dereferenced
|
||||||
|
[m for m in group_obj.members]
|
||||||
|
self.assertEqual(q, 2)
|
||||||
|
self.assertTrue(group_obj._data['members']._dereferenced)
|
||||||
|
|
||||||
# Document select_related
|
# Document select_related
|
||||||
with query_counter() as q:
|
with query_counter() as q:
|
||||||
@ -125,6 +133,46 @@ class FieldTest(unittest.TestCase):
|
|||||||
[m for m in group_obj.members]
|
[m for m in group_obj.members]
|
||||||
self.assertEqual(q, 2)
|
self.assertEqual(q, 2)
|
||||||
|
|
||||||
|
def test_list_item_dereference_orphan_dbref(self):
|
||||||
|
"""Ensure that orphan DBRef items in ListFields are dereferenced.
|
||||||
|
"""
|
||||||
|
class User(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
class Group(Document):
|
||||||
|
members = ListField(ReferenceField(User, dbref=False))
|
||||||
|
|
||||||
|
User.drop_collection()
|
||||||
|
Group.drop_collection()
|
||||||
|
|
||||||
|
for i in range(1, 51):
|
||||||
|
user = User(name='user %s' % i)
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
group = Group(members=User.objects)
|
||||||
|
group.save()
|
||||||
|
group.reload() # Confirm reload works
|
||||||
|
|
||||||
|
# Delete one User so one of the references in the
|
||||||
|
# Group.members list is an orphan DBRef
|
||||||
|
User.objects[0].delete()
|
||||||
|
with query_counter() as q:
|
||||||
|
self.assertEqual(q, 0)
|
||||||
|
|
||||||
|
group_obj = Group.objects.first()
|
||||||
|
self.assertEqual(q, 1)
|
||||||
|
|
||||||
|
[m for m in group_obj.members]
|
||||||
|
self.assertEqual(q, 2)
|
||||||
|
self.assertTrue(group_obj._data['members']._dereferenced)
|
||||||
|
|
||||||
|
# verifies that no additional queries gets executed
|
||||||
|
# if we re-iterate over the ListField once it is
|
||||||
|
# dereferenced
|
||||||
|
[m for m in group_obj.members]
|
||||||
|
self.assertEqual(q, 2)
|
||||||
|
self.assertTrue(group_obj._data['members']._dereferenced)
|
||||||
|
|
||||||
User.drop_collection()
|
User.drop_collection()
|
||||||
Group.drop_collection()
|
Group.drop_collection()
|
||||||
|
|
||||||
@ -505,6 +553,61 @@ class FieldTest(unittest.TestCase):
|
|||||||
for m in group_obj.members:
|
for m in group_obj.members:
|
||||||
self.assertIn('User', m.__class__.__name__)
|
self.assertIn('User', m.__class__.__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def test_generic_reference_orphan_dbref(self):
|
||||||
|
"""Ensure that generic orphan DBRef items in ListFields are dereferenced.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class UserA(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
class UserB(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
class UserC(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
class Group(Document):
|
||||||
|
members = ListField(GenericReferenceField())
|
||||||
|
|
||||||
|
UserA.drop_collection()
|
||||||
|
UserB.drop_collection()
|
||||||
|
UserC.drop_collection()
|
||||||
|
Group.drop_collection()
|
||||||
|
|
||||||
|
members = []
|
||||||
|
for i in range(1, 51):
|
||||||
|
a = UserA(name='User A %s' % i)
|
||||||
|
a.save()
|
||||||
|
|
||||||
|
b = UserB(name='User B %s' % i)
|
||||||
|
b.save()
|
||||||
|
|
||||||
|
c = UserC(name='User C %s' % i)
|
||||||
|
c.save()
|
||||||
|
|
||||||
|
members += [a, b, c]
|
||||||
|
|
||||||
|
group = Group(members=members)
|
||||||
|
group.save()
|
||||||
|
|
||||||
|
# Delete one UserA instance so that there is
|
||||||
|
# an orphan DBRef in the GenericReference ListField
|
||||||
|
UserA.objects[0].delete()
|
||||||
|
with query_counter() as q:
|
||||||
|
self.assertEqual(q, 0)
|
||||||
|
|
||||||
|
group_obj = Group.objects.first()
|
||||||
|
self.assertEqual(q, 1)
|
||||||
|
|
||||||
|
[m for m in group_obj.members]
|
||||||
|
self.assertEqual(q, 4)
|
||||||
|
self.assertTrue(group_obj._data['members']._dereferenced)
|
||||||
|
|
||||||
|
[m for m in group_obj.members]
|
||||||
|
self.assertEqual(q, 4)
|
||||||
|
self.assertTrue(group_obj._data['members']._dereferenced)
|
||||||
|
|
||||||
UserA.drop_collection()
|
UserA.drop_collection()
|
||||||
UserB.drop_collection()
|
UserB.drop_collection()
|
||||||
UserC.drop_collection()
|
UserC.drop_collection()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user