From 88ef872c6f3d808898ddc9c5ad84291a3580648d Mon Sep 17 00:00:00 2001 From: Rik Date: Mon, 2 Sep 2013 18:11:50 +0200 Subject: [PATCH 01/10] Check if undefined fields are supplied on document If an undefined field is supplied to a document instance, a `FieldDoesNotExist` Exception will be raised. --- mongoengine/base/document.py | 11 ++++++++++- mongoengine/errors.py | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py index df06f6aed..2def35f48 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 @@ -61,6 +61,15 @@ def __init__(self, *args, **values): signals.pre_init.send(self.__class__, document=self, values=values) + # Check if there are undefined fields supplied, if so raise an + # Exception. + for var in values.keys(): + if var not in self._fields.keys(): + msg = ( + "The field '{}' does not exist on the document '{}'" + ).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: diff --git a/mongoengine/errors.py b/mongoengine/errors.py index 4b6b562c2..990150da9 100644 --- a/mongoengine/errors.py +++ b/mongoengine/errors.py @@ -40,6 +40,10 @@ class NotUniqueError(OperationError): pass +class FieldDoesNotExist(Exception): + pass + + class ValidationError(AssertionError): """Validation exception. From 9099b1560760e7c0f8c93348917d9ef05f713b16 Mon Sep 17 00:00:00 2001 From: Rik Date: Tue, 3 Sep 2013 11:25:45 +0200 Subject: [PATCH 02/10] check for dynamic document, exclude id pk and _cls --- mongoengine/base/document.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py index 2def35f48..ae9bdc308 100644 --- a/mongoengine/base/document.py +++ b/mongoengine/base/document.py @@ -63,12 +63,13 @@ def __init__(self, *args, **values): # Check if there are undefined fields supplied, if so raise an # Exception. - for var in values.keys(): - if var not in self._fields.keys(): - msg = ( - "The field '{}' does not exist on the document '{}'" - ).format(var, self._class_name) - raise FieldDoesNotExist(msg) + if not self._dynamic: + for var in values.keys(): + if var not in self._fields.keys() + ['id', 'pk', '_cls']: + msg = ( + "The field '{}' does not exist on the document '{}'" + ).format(var, self._class_name) + raise FieldDoesNotExist(msg) if self.STRICT and not self._dynamic: self._data = StrictDict.create(allowed_keys=self._fields_ordered)() From 1308e5d9bf67bdf02e61a96c9663a1c7a6eca613 Mon Sep 17 00:00:00 2001 From: Rik Date: Fri, 27 Jun 2014 14:43:56 +0200 Subject: [PATCH 03/10] fixed tests that were using undefined model fields --- tests/fields/fields.py | 2 ++ tests/queryset/queryset.py | 7 +++++-- tests/test_dereference.py | 2 ++ tests/test_django.py | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/fields/fields.py b/tests/fields/fields.py index d7edea376..4f7fab02f 100644 --- a/tests/fields/fields.py +++ b/tests/fields/fields.py @@ -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() 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() From b5ca4b667418ddf7f938d3eb89e371013d863129 Mon Sep 17 00:00:00 2001 From: Rik Date: Mon, 30 Jun 2014 18:12:23 +0200 Subject: [PATCH 04/10] remove unittest test_no_overwritting_no_data_loss Now that fields need to be defined explicitly, it's not possible to have another property with the same name on a model. https://github.com/MongoEngine/mongoengine/pull/457#issuecomment-47513105 --- tests/document/instance.py | 24 ------------------------ 1 file changed, 24 deletions(-) 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): From 095358232c69c61e815e100b9bb25da8c3d539d8 Mon Sep 17 00:00:00 2001 From: Rik Date: Mon, 30 Jun 2014 18:27:55 +0200 Subject: [PATCH 05/10] add FieldDoesNotExist exception to __all__ So it will be available when you do: from mongoengine import * --- mongoengine/errors.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mongoengine/errors.py b/mongoengine/errors.py index 990150da9..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): From db33385febe7f8cd71e68bbf7543dfc975a63d2b Mon Sep 17 00:00:00 2001 From: Rik Date: Mon, 30 Jun 2014 18:29:02 +0200 Subject: [PATCH 06/10] add test if FieldDoesNotExist is raised When trying to set an undefined field. --- tests/fields/fields.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/fields/fields.py b/tests/fields/fields.py index 4f7fab02f..ae4575ad6 100644 --- a/tests/fields/fields.py +++ b/tests/fields/fields.py @@ -3068,6 +3068,16 @@ 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') + + with self.assertRaises(FieldDoesNotExist): + Doc(bar='test') if __name__ == '__main__': unittest.main() From 9f16260ca03d6a05615e2273febaa177a79b9e3e Mon Sep 17 00:00:00 2001 From: Rik Date: Tue, 1 Jul 2014 14:21:29 +0200 Subject: [PATCH 07/10] using python 2.6 compatible way of assertRaises --- tests/fields/fields.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/fields/fields.py b/tests/fields/fields.py index ae4575ad6..75d698c7e 100644 --- a/tests/fields/fields.py +++ b/tests/fields/fields.py @@ -3076,8 +3076,10 @@ def test_undefined_field_exception(self): class Doc(Document): foo = StringField(db_field='f') - with self.assertRaises(FieldDoesNotExist): + def test(): Doc(bar='test') + self.assertRaises(FieldDoesNotExist, test) + if __name__ == '__main__': unittest.main() From 1696cc68880aaffe24fadaa2d0abb05d10672a86 Mon Sep 17 00:00:00 2001 From: Rik Date: Tue, 1 Jul 2014 15:18:01 +0200 Subject: [PATCH 08/10] added ints in string.format() for 2.6 compability --- mongoengine/base/document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py index ae9bdc308..bc4840f19 100644 --- a/mongoengine/base/document.py +++ b/mongoengine/base/document.py @@ -67,7 +67,7 @@ def __init__(self, *args, **values): for var in values.keys(): if var not in self._fields.keys() + ['id', 'pk', '_cls']: msg = ( - "The field '{}' does not exist on the document '{}'" + "The field '{0}' does not exist on the document '{1}'" ).format(var, self._class_name) raise FieldDoesNotExist(msg) From 1d0eb4399c14fbd27a9464aa5e8e3574fbeb479c Mon Sep 17 00:00:00 2001 From: Rik Date: Thu, 10 Jul 2014 11:48:25 +0200 Subject: [PATCH 09/10] moved initialization of _created before FieldDoesNotExist check Because otherwise we'll get a FieldDoesNotExist error on the field _created. --- mongoengine/base/document.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py index bc4840f19..5063dee5a 100644 --- a/mongoengine/base/document.py +++ b/mongoengine/base/document.py @@ -54,11 +54,14 @@ 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 @@ -77,7 +80,6 @@ def __init__(self, *args, **values): self._data = SemiStrictDict.create( allowed_keys=self._fields_ordered)() - _created = values.pop("_created", True) self._data = {} self._dynamic_fields = SON() From 6bd26efa73664b776dcaac28eeec010a4911a218 Mon Sep 17 00:00:00 2001 From: Rik Date: Tue, 25 Nov 2014 19:29:12 +0100 Subject: [PATCH 10/10] fixed more tests that were using undefined model fields --- tests/fields/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fields/fields.py b/tests/fields/fields.py index 75d698c7e..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") )