Skip to content
16 changes: 14 additions & 2 deletions mongoengine/base/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from mongoengine import signals
from mongoengine.common import _import_class
from mongoengine.errors import (ValidationError, InvalidDocumentError,
LookUpError)
LookUpError, FieldDoesNotExist)
from mongoengine.python_support import PY3, txt_type

from mongoengine.base.common import get_document, ALLOW_INHERITANCE
Expand Down Expand Up @@ -54,20 +54,32 @@ def __init__(self, *args, **values):
raise TypeError(
"Multiple values for keyword argument '" + name + "'")
values[name] = value

__auto_convert = values.pop("__auto_convert", True)

# 399: set default values only to fields loaded from DB
__only_fields = set(values.pop("__only_fields", values))

_created = values.pop("_created", True)

signals.pre_init.send(self.__class__, document=self, values=values)

# Check if there are undefined fields supplied, if so raise an
# Exception.
if not self._dynamic:
for var in values.keys():
if var not in self._fields.keys() + ['id', 'pk', '_cls']:
msg = (
"The field '{0}' does not exist on the document '{1}'"
).format(var, self._class_name)
raise FieldDoesNotExist(msg)

if self.STRICT and not self._dynamic:
self._data = StrictDict.create(allowed_keys=self._fields_ordered)()
else:
self._data = SemiStrictDict.create(
allowed_keys=self._fields_ordered)()

_created = values.pop("_created", True)
self._data = {}
self._dynamic_fields = SON()

Expand Down
7 changes: 6 additions & 1 deletion mongoengine/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

__all__ = ('NotRegistered', 'InvalidDocumentError', 'LookUpError',
'DoesNotExist', 'MultipleObjectsReturned', 'InvalidQueryError',
'OperationError', 'NotUniqueError', 'ValidationError')
'OperationError', 'NotUniqueError', 'FieldDoesNotExist',
'ValidationError')


class NotRegistered(Exception):
Expand Down Expand Up @@ -40,6 +41,10 @@ class NotUniqueError(OperationError):
pass


class FieldDoesNotExist(Exception):
pass


class ValidationError(AssertionError):
"""Validation exception.

Expand Down
24 changes: 0 additions & 24 deletions tests/document/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -2443,30 +2443,6 @@ class Group(Document):
group = Group.objects.first()
self.assertEqual("hello - default", group.name)

def test_no_overwritting_no_data_loss(self):

class User(Document):
username = StringField(primary_key=True)
name = StringField()

@property
def foo(self):
return True

User.drop_collection()

user = User(username="Ross", foo="bar")
self.assertTrue(user.foo)

User._get_collection().save({"_id": "Ross", "foo": "Bar",
"data": [1, 2, 3]})

user = User.objects.first()
self.assertEqual("Ross", user.username)
self.assertEqual(True, user.foo)
self.assertEqual("Bar", user._data["foo"])
self.assertEqual([1, 2, 3], user._data["data"])

def test_spaces_in_keys(self):

class Embedded(DynamicEmbeddedDocument):
Expand Down
18 changes: 16 additions & 2 deletions tests/fields/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -1814,7 +1814,7 @@ class Ocorrence(Document):
Animal.drop_collection()
Ocorrence.drop_collection()

a = Animal(nam="Leopard", tag="heavy",
a = Animal(name="Leopard", tag="heavy",
owner=Owner(tp='u', name="Wilson Júnior")
)
a.save()
Expand Down Expand Up @@ -1864,7 +1864,7 @@ class Ocorrence(Document):
Animal.drop_collection()
Ocorrence.drop_collection()

a = Animal(nam="Leopard", tag="heavy",
a = Animal(name="Leopard", tag="heavy",
owner=Owner(tags=['cool', 'funny'],
name="Wilson Júnior")
)
Expand Down Expand Up @@ -2717,9 +2717,11 @@ def test_multiple_sequence_fields_on_docs(self):

class Animal(Document):
id = SequenceField(primary_key=True)
name = StringField()

class Person(Document):
id = SequenceField(primary_key=True)
name = StringField()

self.db['mongoengine.counters'].drop()
Animal.drop_collection()
Expand Down Expand Up @@ -3066,6 +3068,18 @@ class Doc(Document):
except Exception:
self.fail()

def test_undefined_field_exception(self):
"""Tests if a `FieldDoesNotExist` exception is raised when trying to
set a value to a field that's not defined.
"""

class Doc(Document):
foo = StringField(db_field='f')

def test():
Doc(bar='test')

self.assertRaises(FieldDoesNotExist, test)

if __name__ == '__main__':
unittest.main()
7 changes: 5 additions & 2 deletions tests/queryset/queryset.py
Original file line number Diff line number Diff line change
Expand Up @@ -1492,6 +1492,7 @@ def test_update(self):
"""Ensure that atomic updates work properly.
"""
class BlogPost(Document):
name = StringField()
title = StringField()
hits = IntField()
tags = ListField(StringField())
Expand Down Expand Up @@ -2879,12 +2880,14 @@ class Book(Document):
self.assertEqual(authors, [mark_twain, john_tolkien])

def test_distinct_ListField_ReferenceField(self):
class Foo(Document):
bar_lst = ListField(ReferenceField('Bar'))

class Bar(Document):
text = StringField()

class Foo(Document):
bar = ReferenceField('Bar')
bar_lst = ListField(ReferenceField('Bar'))

Bar.drop_collection()
Foo.drop_collection()

Expand Down
2 changes: 2 additions & 0 deletions tests/test_dereference.py
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,8 @@ def test_multidirectional_lists(self):

class Asset(Document):
name = StringField(max_length=250, required=True)
path = StringField()
title = StringField()
parent = GenericReferenceField(default=None)
parents = ListField(GenericReferenceField())
children = ListField(GenericReferenceField())
Expand Down
2 changes: 1 addition & 1 deletion tests/test_django.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def count(self, with_limit_and_skip=True):

class Note(Document):
meta = dict(queryset_class=LimitCountQuerySet)
text = StringField()
name = StringField()

Note.drop_collection()

Expand Down