Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions mongoengine/base/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
SemiStrictDict, StrictDict)
from mongoengine.base.fields import ComplexBaseField
from mongoengine.common import _import_class
from mongoengine.errors import (FieldDoesNotExist, InvalidDocumentError,
LookUpError, OperationError, ValidationError)
from mongoengine.errors import (FieldDoesNotExist, InvalidDocumentError, LookUpError, OperationError, ValidationError)

__all__ = ('BaseDocument',)

Expand Down Expand Up @@ -675,6 +674,9 @@ def _from_son(cls, son, _auto_dereference=True, only_fields=None, created=False)
if not only_fields:
only_fields = []

if son and not isinstance(son, dict):
raise ValueError("The source SON object needs to be of type 'dict'")

# Get the class name from the document, falling back to the given
# class if unavailable
class_name = son.get('_cls', cls._class_name)
Expand Down
8 changes: 6 additions & 2 deletions mongoengine/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
GeoJsonBaseField, ObjectIdField, get_document)
from mongoengine.connection import DEFAULT_CONNECTION_NAME, get_db
from mongoengine.document import Document, EmbeddedDocument
from mongoengine.errors import DoesNotExist, ValidationError
from mongoengine.errors import DoesNotExist, InvalidQueryError, ValidationError
from mongoengine.python_support import StringIO
from mongoengine.queryset import DO_NOTHING, QuerySet

Expand Down Expand Up @@ -566,7 +566,11 @@ def lookup_member(self, member_name):

def prepare_query_value(self, op, value):
if value is not None and not isinstance(value, self.document_type):
value = self.document_type._from_son(value)
try:
value = self.document_type._from_son(value)
except ValueError:
raise InvalidQueryError("Querying the embedded document '%s' failed, due to an invalid query value" %
(self.document_type._class_name,))
super(EmbeddedDocumentField, self).prepare_query_value(op, value)
return self.to_mongo(value)

Expand Down
4 changes: 4 additions & 0 deletions tests/document/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -1860,6 +1860,10 @@ class Word(Document):
'occurs': {"hello": None}
})

# Tests for issue #1438: https://github.com/MongoEngine/mongoengine/issues/1438
with self.assertRaises(ValueError):
Word._from_son('this is not a valid SON dict')

def test_reverse_delete_rule_cascade_and_nullify(self):
"""Ensure that a referenced document is also deleted upon deletion.
"""
Expand Down
18 changes: 16 additions & 2 deletions tests/queryset/queryset.py
Original file line number Diff line number Diff line change
Expand Up @@ -1266,7 +1266,7 @@ class BlogPost(Document):

def test_find_embedded(self):
"""Ensure that an embedded document is properly returned from
a query.
different manners of querying.
"""
class User(EmbeddedDocument):
name = StringField()
Expand All @@ -1277,15 +1277,29 @@ class BlogPost(Document):

BlogPost.drop_collection()

user = User(name='Test User')
BlogPost.objects.create(
author=User(name='Test User'),
author=user,
content='Had a good coffee today...'
)

result = BlogPost.objects.first()
self.assertTrue(isinstance(result.author, User))
self.assertEqual(result.author.name, 'Test User')

result = BlogPost.objects.get(author__name=user.name)
self.assertTrue(isinstance(result.author, User))
self.assertEqual(result.author.name, 'Test User')

result = BlogPost.objects.get(author={'name': user.name})
self.assertTrue(isinstance(result.author, User))
self.assertEqual(result.author.name, 'Test User')

# Fails, since the string is not a type that is able to represent the
# author's document structure (should be dict)
with self.assertRaises(InvalidQueryError):
BlogPost.objects.get(author=user.name)

def test_find_empty_embedded(self):
"""Ensure that you can save and find an empty embedded document."""
class User(EmbeddedDocument):
Expand Down