diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py index df06f6aed..5063dee5a 100644 --- a/mongoengine/base/document.py +++ b/mongoengine/base/document.py @@ -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 @@ -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() diff --git a/mongoengine/errors.py b/mongoengine/errors.py index 4b6b562c2..6cde7771e 100644 --- a/mongoengine/errors.py +++ b/mongoengine/errors.py @@ -5,7 +5,8 @@ __all__ = ('NotRegistered', 'InvalidDocumentError', 'LookUpError', 'DoesNotExist', 'MultipleObjectsReturned', 'InvalidQueryError', - 'OperationError', 'NotUniqueError', 'ValidationError') + 'OperationError', 'NotUniqueError', 'FieldDoesNotExist', + 'ValidationError') class NotRegistered(Exception): @@ -40,6 +41,10 @@ class NotUniqueError(OperationError): pass +class FieldDoesNotExist(Exception): + pass + + class ValidationError(AssertionError): """Validation exception. diff --git a/tests/document/instance.py b/tests/document/instance.py index 40c25f8df..3c6a9940f 100644 --- a/tests/document/instance.py +++ b/tests/document/instance.py @@ -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): diff --git a/tests/fields/fields.py b/tests/fields/fields.py index d7edea376..a95001b46 100644 --- a/tests/fields/fields.py +++ b/tests/fields/fields.py @@ -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() @@ -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") ) @@ -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() @@ -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() diff --git a/tests/queryset/queryset.py b/tests/queryset/queryset.py index 703728fe1..53f2d8a98 100644 --- a/tests/queryset/queryset.py +++ b/tests/queryset/queryset.py @@ -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()) @@ -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() diff --git a/tests/test_dereference.py b/tests/test_dereference.py index 85588558e..2115b45a5 100644 --- a/tests/test_dereference.py +++ b/tests/test_dereference.py @@ -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()) diff --git a/tests/test_django.py b/tests/test_django.py index c4d3d5829..0070087fb 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -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()