From f6cd349a1698efe85f9501e369d26d8f6ec0b7a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastien=20G=C3=A9rard?= Date: Tue, 30 Oct 2018 22:52:50 +0100 Subject: [PATCH 1/2] Fix bug when using GenericReferenceField, modifications to the referenced document are tracked in the parent #1934 --- docs/changelog.rst | 2 ++ mongoengine/base/document.py | 3 ++- tests/fields/fields.py | 32 +++++++++++++++++++++++++++++--- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 69581a4b..255d3743 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,6 +6,8 @@ Development =========== - QuerySet limit function behaviour: Passing 0 as parameter will return all the documents in the cursor #1611 - bulk insert updates the ids of the input documents #1919 +- Fix an harmless bug related to GenericReferenceField where modifications in the generic-referenced document + were tracked in the parent (#1934) - (Fill this out as you fix issues and develop your features). ======= Changes in 0.15.4 diff --git a/mongoengine/base/document.py b/mongoengine/base/document.py index 66217921..aad027e5 100644 --- a/mongoengine/base/document.py +++ b/mongoengine/base/document.py @@ -528,6 +528,7 @@ class BaseDocument(object): EmbeddedDocument = _import_class('EmbeddedDocument') DynamicEmbeddedDocument = _import_class('DynamicEmbeddedDocument') ReferenceField = _import_class('ReferenceField') + GenericReferenceField = _import_class('GenericReferenceField') SortedListField = _import_class('SortedListField') changed_fields = [] @@ -560,7 +561,7 @@ class BaseDocument(object): elif (isinstance(data, (list, tuple, dict)) and db_field_name not in changed_fields): if (hasattr(field, 'field') and - isinstance(field.field, ReferenceField)): + isinstance(field.field, (ReferenceField, GenericReferenceField))): continue elif isinstance(field, SortedListField) and field._ordering: # if ordering is affected whole list is changed diff --git a/tests/fields/fields.py b/tests/fields/fields.py index b375822e..084be71f 100644 --- a/tests/fields/fields.py +++ b/tests/fields/fields.py @@ -1187,7 +1187,7 @@ class FieldTest(MongoDBTestCase): # aka 'del list[index]' # aka 'operator.delitem(list, index)' reset_post() - del post.info[2] # del from middle ('2') + del post.info[2] # del from middle ('2') self.assertEqual(post.info, ['0', '1', '3', '4', '5']) post.save() post.reload() @@ -1197,7 +1197,7 @@ class FieldTest(MongoDBTestCase): # aka 'del list[i:j]' # aka 'operator.delitem(list, slice(i,j))' reset_post() - del post.info[1:3] # removes '1', '2' + del post.info[1:3] # removes '1', '2' self.assertEqual(post.info, ['0', '3', '4', '5']) post.save() post.reload() @@ -2816,7 +2816,32 @@ class FieldTest(MongoDBTestCase): doc = Doc.objects.get(ref=DBRef('doc', doc1.pk)) self.assertEqual(doc, doc2) - def test_generic_reference_filter_by_objectid(self): + def test_generic_reference_is_not_tracked_in_parent_doc(self): + """Ensure that modifications of related documents (through generic reference) don't influence + the owner changed fields (#1934) + """ + class Doc1(Document): + name = StringField() + + class Doc2(Document): + ref = GenericReferenceField() + refs = ListField(GenericReferenceField()) + + Doc1.drop_collection() + Doc2.drop_collection() + + doc1 = Doc1(name='garbage1').save() + doc11 = Doc1(name='garbage11').save() + doc2 = Doc2(ref=doc1, refs=[doc11]).save() + + doc2.ref.name = 'garbage2' + self.assertEqual(doc2._get_changed_fields(), []) + + doc2.refs[0].name = 'garbage3' + self.assertEqual(doc2._get_changed_fields(), []) + self.assertEqual(doc2._delta(), ({}, {})) + + def test_generic_reference_field(self): """Ensure we can search for a specific generic reference by providing its DBRef. """ @@ -4348,6 +4373,7 @@ class TestEmbeddedDocumentField(MongoDBTestCase): class MyFailingdoc2(Document): emb = EmbeddedDocumentField('MyDoc') + class CachedReferenceFieldTest(MongoDBTestCase): def test_cached_reference_field_get_and_save(self): From 983474b2bdc33cc5550d8c9e2c45b166c64bd029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastien=20G=C3=A9rard?= Date: Tue, 30 Oct 2018 23:40:46 +0100 Subject: [PATCH 2/2] Ignore 2 more flake8 warnings (introduced in latest flake8 3.6.0 release) --- mongoengine/queryset/base.py | 4 ++-- setup.cfg | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mongoengine/queryset/base.py b/mongoengine/queryset/base.py index 9ea214cc..6c36d984 100644 --- a/mongoengine/queryset/base.py +++ b/mongoengine/queryset/base.py @@ -1872,8 +1872,8 @@ class BaseQuerySet(object): # Substitute the correct name for the field into the javascript return '.'.join([f.db_field for f in fields]) - code = re.sub(u'\[\s*~([A-z_][A-z_0-9.]+?)\s*\]', field_sub, code) - code = re.sub(u'\{\{\s*~([A-z_][A-z_0-9.]+?)\s*\}\}', field_path_sub, + code = re.sub(r'\[\s*~([A-z_][A-z_0-9.]+?)\s*\]', field_sub, code) + code = re.sub(r'\{\{\s*~([A-z_][A-z_0-9.]+?)\s*\}\}', field_path_sub, code) return code diff --git a/setup.cfg b/setup.cfg index fd6192b8..84086601 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,7 +5,7 @@ detailed-errors=1 cover-package=mongoengine [flake8] -ignore=E501,F401,F403,F405,I201,I202 +ignore=E501,F401,F403,F405,I201,I202,W504, W605 exclude=build,dist,docs,venv,venv3,.tox,.eggs,tests max-complexity=47 application-import-names=mongoengine,tests