Merge pull request #1892 from bagerard/no_dereference_queryset_fix_side_effect
fix side effect from queryset.no_dereference
This commit is contained in:
commit
708d1c7a32
@ -700,7 +700,7 @@ class BaseDocument(object):
|
|||||||
|
|
||||||
fields = cls._fields
|
fields = cls._fields
|
||||||
if not _auto_dereference:
|
if not _auto_dereference:
|
||||||
fields = copy.copy(fields)
|
fields = copy.deepcopy(fields)
|
||||||
|
|
||||||
for field_name, field in fields.iteritems():
|
for field_name, field in fields.iteritems():
|
||||||
field._auto_dereference = _auto_dereference
|
field._auto_dereference = _auto_dereference
|
||||||
|
@ -266,13 +266,15 @@ class ComplexBaseField(BaseField):
|
|||||||
ReferenceField = _import_class('ReferenceField')
|
ReferenceField = _import_class('ReferenceField')
|
||||||
GenericReferenceField = _import_class('GenericReferenceField')
|
GenericReferenceField = _import_class('GenericReferenceField')
|
||||||
EmbeddedDocumentListField = _import_class('EmbeddedDocumentListField')
|
EmbeddedDocumentListField = _import_class('EmbeddedDocumentListField')
|
||||||
dereference = (self._auto_dereference and
|
|
||||||
|
auto_dereference = instance._fields[self.name]._auto_dereference
|
||||||
|
|
||||||
|
dereference = (auto_dereference and
|
||||||
(self.field is None or isinstance(self.field,
|
(self.field is None or isinstance(self.field,
|
||||||
(GenericReferenceField, ReferenceField))))
|
(GenericReferenceField, ReferenceField))))
|
||||||
|
|
||||||
_dereference = _import_class('DeReference')()
|
_dereference = _import_class('DeReference')()
|
||||||
|
|
||||||
self._auto_dereference = instance._fields[self.name]._auto_dereference
|
|
||||||
if instance._initialised and dereference and instance._data.get(self.name):
|
if instance._initialised and dereference and instance._data.get(self.name):
|
||||||
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,
|
||||||
@ -293,7 +295,7 @@ class ComplexBaseField(BaseField):
|
|||||||
value = BaseDict(value, instance, self.name)
|
value = BaseDict(value, instance, self.name)
|
||||||
instance._data[self.name] = value
|
instance._data[self.name] = value
|
||||||
|
|
||||||
if (self._auto_dereference and instance._initialised and
|
if (auto_dereference and instance._initialised and
|
||||||
isinstance(value, (BaseList, BaseDict)) and
|
isinstance(value, (BaseList, BaseDict)) and
|
||||||
not value._dereferenced):
|
not value._dereferenced):
|
||||||
value = _dereference(
|
value = _dereference(
|
||||||
|
@ -1104,9 +1104,9 @@ class ReferenceField(BaseField):
|
|||||||
|
|
||||||
# Get value from document instance if available
|
# Get value from document instance if available
|
||||||
value = instance._data.get(self.name)
|
value = instance._data.get(self.name)
|
||||||
self._auto_dereference = instance._fields[self.name]._auto_dereference
|
auto_dereference = instance._fields[self.name]._auto_dereference
|
||||||
# Dereference DBRefs
|
# Dereference DBRefs
|
||||||
if self._auto_dereference and isinstance(value, DBRef):
|
if auto_dereference and isinstance(value, DBRef):
|
||||||
if hasattr(value, 'cls'):
|
if hasattr(value, 'cls'):
|
||||||
# Dereference using the class type specified in the reference
|
# Dereference using the class type specified in the reference
|
||||||
cls = get_document(value.cls)
|
cls = get_document(value.cls)
|
||||||
@ -1267,6 +1267,7 @@ class CachedReferenceField(BaseField):
|
|||||||
# Get value from document instance if available
|
# Get value from document instance if available
|
||||||
value = instance._data.get(self.name)
|
value = instance._data.get(self.name)
|
||||||
self._auto_dereference = instance._fields[self.name]._auto_dereference
|
self._auto_dereference = instance._fields[self.name]._auto_dereference
|
||||||
|
|
||||||
# Dereference DBRefs
|
# Dereference DBRefs
|
||||||
if self._auto_dereference and isinstance(value, DBRef):
|
if self._auto_dereference and isinstance(value, DBRef):
|
||||||
dereferenced = self.document_type._get_db().dereference(value)
|
dereferenced = self.document_type._get_db().dereference(value)
|
||||||
|
@ -4674,11 +4674,69 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
User(name="Bob Dole", organization=whitehouse).save()
|
User(name="Bob Dole", organization=whitehouse).save()
|
||||||
|
|
||||||
qs = User.objects()
|
qs = User.objects()
|
||||||
|
qs_user = qs.first()
|
||||||
|
|
||||||
self.assertIsInstance(qs.first().organization, Organization)
|
self.assertIsInstance(qs.first().organization, Organization)
|
||||||
self.assertNotIsInstance(qs.no_dereference().first().organization, Organization)
|
|
||||||
self.assertNotIsInstance(qs.no_dereference().get().organization, Organization)
|
self.assertIsInstance(qs.no_dereference().first().organization, DBRef)
|
||||||
|
|
||||||
|
self.assertIsInstance(qs_user.organization, Organization)
|
||||||
self.assertIsInstance(qs.first().organization, Organization)
|
self.assertIsInstance(qs.first().organization, Organization)
|
||||||
|
|
||||||
|
def test_no_dereference_internals(self):
|
||||||
|
# Test the internals on which queryset.no_dereference relies on
|
||||||
|
class Organization(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
class User(Document):
|
||||||
|
organization = ReferenceField(Organization)
|
||||||
|
|
||||||
|
User.drop_collection()
|
||||||
|
Organization.drop_collection()
|
||||||
|
|
||||||
|
cls_organization_field = User.organization
|
||||||
|
self.assertTrue(cls_organization_field._auto_dereference, True) # default
|
||||||
|
|
||||||
|
org = Organization(name="whatever").save()
|
||||||
|
User(organization=org).save()
|
||||||
|
|
||||||
|
qs_no_deref = User.objects().no_dereference()
|
||||||
|
user_no_deref = qs_no_deref.first()
|
||||||
|
self.assertFalse(qs_no_deref._auto_dereference)
|
||||||
|
|
||||||
|
# Make sure the instance field is different from the class field
|
||||||
|
instance_org_field = user_no_deref._fields['organization']
|
||||||
|
self.assertIsNot(instance_org_field, cls_organization_field)
|
||||||
|
self.assertFalse(instance_org_field._auto_dereference)
|
||||||
|
|
||||||
|
self.assertIsInstance(user_no_deref.organization, DBRef)
|
||||||
|
self.assertTrue(cls_organization_field._auto_dereference, True) # Make sure the class Field wasn't altered
|
||||||
|
|
||||||
|
def test_no_dereference_no_side_effect_on_existing_instance(self):
|
||||||
|
# Relates to issue #1677 - ensures no regression of the bug
|
||||||
|
|
||||||
|
class Organization(Document):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
class User(Document):
|
||||||
|
organization = ReferenceField(Organization)
|
||||||
|
|
||||||
|
User.drop_collection()
|
||||||
|
Organization.drop_collection()
|
||||||
|
|
||||||
|
org = Organization(name="whatever").save()
|
||||||
|
User(organization=org).save()
|
||||||
|
|
||||||
|
qs = User.objects()
|
||||||
|
user = qs.first()
|
||||||
|
|
||||||
|
qs_no_deref = User.objects().no_dereference()
|
||||||
|
user_no_deref = qs_no_deref.first()
|
||||||
|
|
||||||
|
no_derf_org = user_no_deref.organization # was triggering the bug
|
||||||
|
self.assertIsInstance(no_derf_org, DBRef)
|
||||||
|
self.assertIsInstance(user.organization, Organization)
|
||||||
|
|
||||||
def test_no_dereference_embedded_doc(self):
|
def test_no_dereference_embedded_doc(self):
|
||||||
|
|
||||||
class User(Document):
|
class User(Document):
|
||||||
@ -4693,7 +4751,7 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
members = ListField(EmbeddedDocumentField(Member))
|
members = ListField(EmbeddedDocumentField(Member))
|
||||||
ceo = ReferenceField(User)
|
ceo = ReferenceField(User)
|
||||||
member = EmbeddedDocumentField(Member)
|
member = EmbeddedDocumentField(Member)
|
||||||
admin = ListField(ReferenceField(User))
|
admins = ListField(ReferenceField(User))
|
||||||
|
|
||||||
Organization.drop_collection()
|
Organization.drop_collection()
|
||||||
User.drop_collection()
|
User.drop_collection()
|
||||||
@ -4703,16 +4761,22 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
|
|
||||||
member = Member(name="Flash", user=user)
|
member = Member(name="Flash", user=user)
|
||||||
|
|
||||||
company = Organization(name="Mongo Inc", ceo=user, member=member)
|
company = Organization(name="Mongo Inc",
|
||||||
company.admin.append(user)
|
ceo=user,
|
||||||
company.members.append(member)
|
member=member,
|
||||||
|
admins=[user],
|
||||||
|
members=[member])
|
||||||
company.save()
|
company.save()
|
||||||
|
|
||||||
result = Organization.objects().no_dereference().first()
|
org = Organization.objects().no_dereference().first()
|
||||||
|
|
||||||
self.assertIsInstance(result.admin[0], (DBRef, ObjectId))
|
self.assertNotEqual(id(org._fields['admins']), id(Organization.admins))
|
||||||
self.assertIsInstance(result.member.user, (DBRef, ObjectId))
|
self.assertFalse(org._fields['admins']._auto_dereference)
|
||||||
self.assertIsInstance(result.members[0].user, (DBRef, ObjectId))
|
|
||||||
|
admin = org.admins[0]
|
||||||
|
self.assertIsInstance(admin, DBRef)
|
||||||
|
self.assertIsInstance(org.member.user, DBRef)
|
||||||
|
self.assertIsInstance(org.members[0].user, DBRef)
|
||||||
|
|
||||||
def test_cached_queryset(self):
|
def test_cached_queryset(self):
|
||||||
class Person(Document):
|
class Person(Document):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user