Compare commits
26 Commits
v0.15.0
...
revert-164
Author | SHA1 | Date | |
---|---|---|---|
|
18a5fba42b | ||
|
b5a3b6f86a | ||
|
2f088ce29e | ||
|
ff408c604b | ||
|
7674dc9b34 | ||
|
9e0ca51c2f | ||
|
961629d156 | ||
|
2cbebf9c99 | ||
|
08a4deca17 | ||
|
ce9ea7baad | ||
|
b35efb9f72 | ||
|
c45dfacb41 | ||
|
91152a7977 | ||
|
0ce081323f | ||
|
79486e3393 | ||
|
60758dd76b | ||
|
e74f659015 | ||
|
c1c09fa6b4 | ||
|
47c7cb9327 | ||
|
4d6256e1a1 | ||
|
13180d92e3 | ||
|
9ab856e186 | ||
|
aa4996ef28 | ||
|
be8f1b9fdd | ||
|
ba99190f53 | ||
|
70088704e2 |
@@ -2,6 +2,13 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
dev
|
||||||
|
===
|
||||||
|
- Subfield resolve error in generic_emdedded_document query #1651 #1652
|
||||||
|
- use each modifier only with $position #1673 #1675
|
||||||
|
- Improve LazyReferenceField and GenericLazyReferenceField with nested fields #1704
|
||||||
|
- Fix validation error instance in GenericEmbeddedDocumentField #1067
|
||||||
|
|
||||||
Changes in 0.15.0
|
Changes in 0.15.0
|
||||||
=================
|
=================
|
||||||
- Add LazyReferenceField and GenericLazyReferenceField to address #1230
|
- Add LazyReferenceField and GenericLazyReferenceField to address #1230
|
||||||
|
@@ -153,7 +153,7 @@ post. This works, but there is no real reason to be storing the comments
|
|||||||
separately from their associated posts, other than to work around the
|
separately from their associated posts, other than to work around the
|
||||||
relational model. Using MongoDB we can store the comments as a list of
|
relational model. Using MongoDB we can store the comments as a list of
|
||||||
*embedded documents* directly on a post document. An embedded document should
|
*embedded documents* directly on a post document. An embedded document should
|
||||||
be treated no differently that a regular document; it just doesn't have its own
|
be treated no differently than a regular document; it just doesn't have its own
|
||||||
collection in the database. Using MongoEngine, we can define the structure of
|
collection in the database. Using MongoEngine, we can define the structure of
|
||||||
embedded documents, along with utility methods, in exactly the same way we do
|
embedded documents, along with utility methods, in exactly the same way we do
|
||||||
with regular documents::
|
with regular documents::
|
||||||
|
@@ -13,6 +13,7 @@ from mongoengine import signals
|
|||||||
from mongoengine.base.common import get_document
|
from mongoengine.base.common import get_document
|
||||||
from mongoengine.base.datastructures import (BaseDict, BaseList,
|
from mongoengine.base.datastructures import (BaseDict, BaseList,
|
||||||
EmbeddedDocumentList,
|
EmbeddedDocumentList,
|
||||||
|
LazyReference,
|
||||||
StrictDict)
|
StrictDict)
|
||||||
from mongoengine.base.fields import ComplexBaseField
|
from mongoengine.base.fields import ComplexBaseField
|
||||||
from mongoengine.common import _import_class
|
from mongoengine.common import _import_class
|
||||||
@@ -488,7 +489,7 @@ class BaseDocument(object):
|
|||||||
else:
|
else:
|
||||||
data = getattr(data, part, None)
|
data = getattr(data, part, None)
|
||||||
|
|
||||||
if hasattr(data, '_changed_fields'):
|
if not isinstance(data, LazyReference) and hasattr(data, '_changed_fields'):
|
||||||
if getattr(data, '_is_document', False):
|
if getattr(data, '_is_document', False):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@@ -3,6 +3,7 @@ import six
|
|||||||
|
|
||||||
from mongoengine.base import (BaseDict, BaseList, EmbeddedDocumentList,
|
from mongoengine.base import (BaseDict, BaseList, EmbeddedDocumentList,
|
||||||
TopLevelDocumentMetaclass, get_document)
|
TopLevelDocumentMetaclass, get_document)
|
||||||
|
from mongoengine.base.datastructures import LazyReference
|
||||||
from mongoengine.connection import get_db
|
from mongoengine.connection import get_db
|
||||||
from mongoengine.document import Document, EmbeddedDocument
|
from mongoengine.document import Document, EmbeddedDocument
|
||||||
from mongoengine.fields import DictField, ListField, MapField, ReferenceField
|
from mongoengine.fields import DictField, ListField, MapField, ReferenceField
|
||||||
@@ -99,7 +100,10 @@ class DeReference(object):
|
|||||||
if isinstance(item, (Document, EmbeddedDocument)):
|
if isinstance(item, (Document, EmbeddedDocument)):
|
||||||
for field_name, field in item._fields.iteritems():
|
for field_name, field in item._fields.iteritems():
|
||||||
v = item._data.get(field_name, None)
|
v = item._data.get(field_name, None)
|
||||||
if isinstance(v, DBRef):
|
if isinstance(v, LazyReference):
|
||||||
|
# LazyReference inherits DBRef but should not be dereferenced here !
|
||||||
|
continue
|
||||||
|
elif isinstance(v, DBRef):
|
||||||
reference_map.setdefault(field.document_type, set()).add(v.id)
|
reference_map.setdefault(field.document_type, set()).add(v.id)
|
||||||
elif isinstance(v, (dict, SON)) and '_ref' in v:
|
elif isinstance(v, (dict, SON)) and '_ref' in v:
|
||||||
reference_map.setdefault(get_document(v['_cls']), set()).add(v['_ref'].id)
|
reference_map.setdefault(get_document(v['_cls']), set()).add(v['_ref'].id)
|
||||||
@@ -110,6 +114,9 @@ class DeReference(object):
|
|||||||
if isinstance(field_cls, (Document, TopLevelDocumentMetaclass)):
|
if isinstance(field_cls, (Document, TopLevelDocumentMetaclass)):
|
||||||
key = field_cls
|
key = field_cls
|
||||||
reference_map.setdefault(key, set()).update(refs)
|
reference_map.setdefault(key, set()).update(refs)
|
||||||
|
elif isinstance(item, LazyReference):
|
||||||
|
# LazyReference inherits DBRef but should not be dereferenced here !
|
||||||
|
continue
|
||||||
elif isinstance(item, DBRef):
|
elif isinstance(item, DBRef):
|
||||||
reference_map.setdefault(item.collection, set()).add(item.id)
|
reference_map.setdefault(item.collection, set()).add(item.id)
|
||||||
elif isinstance(item, (dict, SON)) and '_ref' in item:
|
elif isinstance(item, (dict, SON)) and '_ref' in item:
|
||||||
|
@@ -28,6 +28,7 @@ except ImportError:
|
|||||||
from mongoengine.base import (BaseDocument, BaseField, ComplexBaseField,
|
from mongoengine.base import (BaseDocument, BaseField, ComplexBaseField,
|
||||||
GeoJsonBaseField, LazyReference, ObjectIdField,
|
GeoJsonBaseField, LazyReference, ObjectIdField,
|
||||||
get_document)
|
get_document)
|
||||||
|
from mongoengine.common import _import_class
|
||||||
from mongoengine.connection import DEFAULT_CONNECTION_NAME, get_db
|
from mongoengine.connection import DEFAULT_CONNECTION_NAME, get_db
|
||||||
from mongoengine.document import Document, EmbeddedDocument
|
from mongoengine.document import Document, EmbeddedDocument
|
||||||
from mongoengine.errors import DoesNotExist, InvalidQueryError, ValidationError
|
from mongoengine.errors import DoesNotExist, InvalidQueryError, ValidationError
|
||||||
@@ -688,16 +689,28 @@ class GenericEmbeddedDocumentField(BaseField):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
def validate(self, value, clean=True):
|
def validate(self, value, clean=True):
|
||||||
|
if self.choices and isinstance(value, SON):
|
||||||
|
for choice in self.choices:
|
||||||
|
if value['_cls'] == choice._class_name:
|
||||||
|
return True
|
||||||
|
|
||||||
if not isinstance(value, EmbeddedDocument):
|
if not isinstance(value, EmbeddedDocument):
|
||||||
self.error('Invalid embedded document instance provided to an '
|
self.error('Invalid embedded document instance provided to an '
|
||||||
'GenericEmbeddedDocumentField')
|
'GenericEmbeddedDocumentField')
|
||||||
|
|
||||||
value.validate(clean=clean)
|
value.validate(clean=clean)
|
||||||
|
|
||||||
|
def lookup_member(self, member_name):
|
||||||
|
if self.choices:
|
||||||
|
for choice in self.choices:
|
||||||
|
field = choice._fields.get(member_name)
|
||||||
|
if field:
|
||||||
|
return field
|
||||||
|
return None
|
||||||
|
|
||||||
def to_mongo(self, document, use_db_field=True, fields=None):
|
def to_mongo(self, document, use_db_field=True, fields=None):
|
||||||
if document is None:
|
if document is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
data = document.to_mongo(use_db_field, fields)
|
data = document.to_mongo(use_db_field, fields)
|
||||||
if '_cls' not in data:
|
if '_cls' not in data:
|
||||||
data['_cls'] = document._class_name
|
data['_cls'] = document._class_name
|
||||||
@@ -781,6 +794,17 @@ class ListField(ComplexBaseField):
|
|||||||
kwargs.setdefault('default', lambda: [])
|
kwargs.setdefault('default', lambda: [])
|
||||||
super(ListField, self).__init__(**kwargs)
|
super(ListField, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def __get__(self, instance, owner):
|
||||||
|
if instance is None:
|
||||||
|
# Document class being used rather than a document object
|
||||||
|
return self
|
||||||
|
value = instance._data.get(self.name)
|
||||||
|
LazyReferenceField = _import_class('LazyReferenceField')
|
||||||
|
GenericLazyReferenceField = _import_class('GenericLazyReferenceField')
|
||||||
|
if isinstance(self.field, (LazyReferenceField, GenericLazyReferenceField)) and value:
|
||||||
|
instance._data[self.name] = [self.field.build_lazyref(x) for x in value]
|
||||||
|
return super(ListField, self).__get__(instance, owner)
|
||||||
|
|
||||||
def validate(self, value):
|
def validate(self, value):
|
||||||
"""Make sure that a list of valid fields is being used."""
|
"""Make sure that a list of valid fields is being used."""
|
||||||
if (not isinstance(value, (list, tuple, QuerySet)) or
|
if (not isinstance(value, (list, tuple, QuerySet)) or
|
||||||
@@ -2203,17 +2227,10 @@ class LazyReferenceField(BaseField):
|
|||||||
self.document_type_obj = get_document(self.document_type_obj)
|
self.document_type_obj = get_document(self.document_type_obj)
|
||||||
return self.document_type_obj
|
return self.document_type_obj
|
||||||
|
|
||||||
def __get__(self, instance, owner):
|
def build_lazyref(self, value):
|
||||||
"""Descriptor to allow lazy dereferencing."""
|
|
||||||
if instance is None:
|
|
||||||
# Document class being used rather than a document object
|
|
||||||
return self
|
|
||||||
|
|
||||||
value = instance._data.get(self.name)
|
|
||||||
if isinstance(value, LazyReference):
|
if isinstance(value, LazyReference):
|
||||||
if value.passthrough != self.passthrough:
|
if value.passthrough != self.passthrough:
|
||||||
instance._data[self.name] = LazyReference(
|
value = LazyReference(value.document_type, value.pk, passthrough=self.passthrough)
|
||||||
value.document_type, value.pk, passthrough=self.passthrough)
|
|
||||||
elif value is not None:
|
elif value is not None:
|
||||||
if isinstance(value, self.document_type):
|
if isinstance(value, self.document_type):
|
||||||
value = LazyReference(self.document_type, value.pk, passthrough=self.passthrough)
|
value = LazyReference(self.document_type, value.pk, passthrough=self.passthrough)
|
||||||
@@ -2222,6 +2239,16 @@ class LazyReferenceField(BaseField):
|
|||||||
else:
|
else:
|
||||||
# value is the primary key of the referenced document
|
# value is the primary key of the referenced document
|
||||||
value = LazyReference(self.document_type, value, passthrough=self.passthrough)
|
value = LazyReference(self.document_type, value, passthrough=self.passthrough)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def __get__(self, instance, owner):
|
||||||
|
"""Descriptor to allow lazy dereferencing."""
|
||||||
|
if instance is None:
|
||||||
|
# Document class being used rather than a document object
|
||||||
|
return self
|
||||||
|
|
||||||
|
value = self.build_lazyref(instance._data.get(self.name))
|
||||||
|
if value:
|
||||||
instance._data[self.name] = value
|
instance._data[self.name] = value
|
||||||
|
|
||||||
return super(LazyReferenceField, self).__get__(instance, owner)
|
return super(LazyReferenceField, self).__get__(instance, owner)
|
||||||
@@ -2246,7 +2273,7 @@ class LazyReferenceField(BaseField):
|
|||||||
|
|
||||||
def validate(self, value):
|
def validate(self, value):
|
||||||
if isinstance(value, LazyReference):
|
if isinstance(value, LazyReference):
|
||||||
if not issubclass(value.document_type, self.document_type):
|
if value.collection != self.document_type._get_collection_name():
|
||||||
self.error('Reference must be on a `%s` document.' % self.document_type)
|
self.error('Reference must be on a `%s` document.' % self.document_type)
|
||||||
pk = value.pk
|
pk = value.pk
|
||||||
elif isinstance(value, self.document_type):
|
elif isinstance(value, self.document_type):
|
||||||
@@ -2306,23 +2333,26 @@ class GenericLazyReferenceField(GenericReferenceField):
|
|||||||
|
|
||||||
def _validate_choices(self, value):
|
def _validate_choices(self, value):
|
||||||
if isinstance(value, LazyReference):
|
if isinstance(value, LazyReference):
|
||||||
value = value.document_type
|
value = value.document_type._class_name
|
||||||
super(GenericLazyReferenceField, self)._validate_choices(value)
|
super(GenericLazyReferenceField, self)._validate_choices(value)
|
||||||
|
|
||||||
def __get__(self, instance, owner):
|
def build_lazyref(self, value):
|
||||||
if instance is None:
|
|
||||||
return self
|
|
||||||
|
|
||||||
value = instance._data.get(self.name)
|
|
||||||
if isinstance(value, LazyReference):
|
if isinstance(value, LazyReference):
|
||||||
if value.passthrough != self.passthrough:
|
if value.passthrough != self.passthrough:
|
||||||
instance._data[self.name] = LazyReference(
|
value = LazyReference(value.document_type, value.pk, passthrough=self.passthrough)
|
||||||
value.document_type, value.pk, passthrough=self.passthrough)
|
|
||||||
elif value is not None:
|
elif value is not None:
|
||||||
if isinstance(value, (dict, SON)):
|
if isinstance(value, (dict, SON)):
|
||||||
value = LazyReference(get_document(value['_cls']), value['_ref'].id, passthrough=self.passthrough)
|
value = LazyReference(get_document(value['_cls']), value['_ref'].id, passthrough=self.passthrough)
|
||||||
elif isinstance(value, Document):
|
elif isinstance(value, Document):
|
||||||
value = LazyReference(type(value), value.pk, passthrough=self.passthrough)
|
value = LazyReference(type(value), value.pk, passthrough=self.passthrough)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def __get__(self, instance, owner):
|
||||||
|
if instance is None:
|
||||||
|
return self
|
||||||
|
|
||||||
|
value = self.build_lazyref(instance._data.get(self.name))
|
||||||
|
if value:
|
||||||
instance._data[self.name] = value
|
instance._data[self.name] = value
|
||||||
|
|
||||||
return super(GenericLazyReferenceField, self).__get__(instance, owner)
|
return super(GenericLazyReferenceField, self).__get__(instance, owner)
|
||||||
@@ -2340,7 +2370,7 @@ class GenericLazyReferenceField(GenericReferenceField):
|
|||||||
if isinstance(document, LazyReference):
|
if isinstance(document, LazyReference):
|
||||||
return SON((
|
return SON((
|
||||||
('_cls', document.document_type._class_name),
|
('_cls', document.document_type._class_name),
|
||||||
('_ref', document)
|
('_ref', DBRef(document.document_type._get_collection_name(), document.pk))
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
return super(GenericLazyReferenceField, self).to_mongo(document)
|
return super(GenericLazyReferenceField, self).to_mongo(document)
|
||||||
|
@@ -344,8 +344,6 @@ def update(_doc_cls=None, **update):
|
|||||||
if not isinstance(value, (set, tuple, list)):
|
if not isinstance(value, (set, tuple, list)):
|
||||||
value = [value]
|
value = [value]
|
||||||
value = {key: {'$each': value, '$position': position}}
|
value = {key: {'$each': value, '$position': position}}
|
||||||
elif isinstance(value, list):
|
|
||||||
value = {key: {'$each': value}}
|
|
||||||
else:
|
else:
|
||||||
value = {key: value}
|
value = {key: value}
|
||||||
else:
|
else:
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
[nosetests]
|
[nosetests]
|
||||||
verbosity=2
|
verbosity=2
|
||||||
detailed-errors=1
|
detailed-errors=1
|
||||||
tests=tests
|
#tests=tests
|
||||||
cover-package=mongoengine
|
cover-package=mongoengine
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore=E501,F401,F403,F405,I201
|
ignore=E501,F401,F403,F405,I201,I202
|
||||||
exclude=build,dist,docs,venv,venv3,.tox,.eggs,tests
|
exclude=build,dist,docs,venv,venv3,.tox,.eggs,tests
|
||||||
max-complexity=47
|
max-complexity=47
|
||||||
application-import-names=mongoengine,tests
|
application-import-names=mongoengine,tests
|
||||||
|
@@ -3183,6 +3183,17 @@ class InstanceTest(unittest.TestCase):
|
|||||||
blog.reload()
|
blog.reload()
|
||||||
self.assertEqual(blog.tags, ['mongodb', 'code', 'python'])
|
self.assertEqual(blog.tags, ['mongodb', 'code', 'python'])
|
||||||
|
|
||||||
|
def test_push_nested_list(self):
|
||||||
|
"""Ensure that push update works in nested list"""
|
||||||
|
class BlogPost(Document):
|
||||||
|
slug = StringField()
|
||||||
|
tags = ListField()
|
||||||
|
|
||||||
|
blog = BlogPost(slug="test").save()
|
||||||
|
blog.update(push__tags=["value1", 123])
|
||||||
|
blog.reload()
|
||||||
|
self.assertEqual(blog.tags, [["value1", 123]])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@@ -4871,6 +4871,48 @@ class LazyReferenceFieldTest(MongoDBTestCase):
|
|||||||
self.assertNotEqual(animal, other_animalref)
|
self.assertNotEqual(animal, other_animalref)
|
||||||
self.assertNotEqual(other_animalref, animal)
|
self.assertNotEqual(other_animalref, animal)
|
||||||
|
|
||||||
|
def test_lazy_reference_embedded(self):
|
||||||
|
class Animal(Document):
|
||||||
|
name = StringField()
|
||||||
|
tag = StringField()
|
||||||
|
|
||||||
|
class EmbeddedOcurrence(EmbeddedDocument):
|
||||||
|
in_list = ListField(LazyReferenceField(Animal))
|
||||||
|
direct = LazyReferenceField(Animal)
|
||||||
|
|
||||||
|
class Ocurrence(Document):
|
||||||
|
in_list = ListField(LazyReferenceField(Animal))
|
||||||
|
in_embedded = EmbeddedDocumentField(EmbeddedOcurrence)
|
||||||
|
direct = LazyReferenceField(Animal)
|
||||||
|
|
||||||
|
Animal.drop_collection()
|
||||||
|
Ocurrence.drop_collection()
|
||||||
|
|
||||||
|
animal1 = Animal('doggo').save()
|
||||||
|
animal2 = Animal('cheeta').save()
|
||||||
|
|
||||||
|
def check_fields_type(occ):
|
||||||
|
self.assertIsInstance(occ.direct, LazyReference)
|
||||||
|
for elem in occ.in_list:
|
||||||
|
self.assertIsInstance(elem, LazyReference)
|
||||||
|
self.assertIsInstance(occ.in_embedded.direct, LazyReference)
|
||||||
|
for elem in occ.in_embedded.in_list:
|
||||||
|
self.assertIsInstance(elem, LazyReference)
|
||||||
|
|
||||||
|
occ = Ocurrence(
|
||||||
|
in_list=[animal1, animal2],
|
||||||
|
in_embedded={'in_list': [animal1, animal2], 'direct': animal1},
|
||||||
|
direct=animal1
|
||||||
|
).save()
|
||||||
|
check_fields_type(occ)
|
||||||
|
occ.reload()
|
||||||
|
check_fields_type(occ)
|
||||||
|
occ.direct = animal1.id
|
||||||
|
occ.in_list = [animal1.id, animal2.id]
|
||||||
|
occ.in_embedded.direct = animal1.id
|
||||||
|
occ.in_embedded.in_list = [animal1.id, animal2.id]
|
||||||
|
check_fields_type(occ)
|
||||||
|
|
||||||
|
|
||||||
class GenericLazyReferenceFieldTest(MongoDBTestCase):
|
class GenericLazyReferenceFieldTest(MongoDBTestCase):
|
||||||
def test_generic_lazy_reference_simple(self):
|
def test_generic_lazy_reference_simple(self):
|
||||||
@@ -5051,6 +5093,50 @@ class GenericLazyReferenceFieldTest(MongoDBTestCase):
|
|||||||
p = Ocurrence.objects.get()
|
p = Ocurrence.objects.get()
|
||||||
self.assertIs(p.animal, None)
|
self.assertIs(p.animal, None)
|
||||||
|
|
||||||
|
def test_generic_lazy_reference_embedded(self):
|
||||||
|
class Animal(Document):
|
||||||
|
name = StringField()
|
||||||
|
tag = StringField()
|
||||||
|
|
||||||
|
class EmbeddedOcurrence(EmbeddedDocument):
|
||||||
|
in_list = ListField(GenericLazyReferenceField())
|
||||||
|
direct = GenericLazyReferenceField()
|
||||||
|
|
||||||
|
class Ocurrence(Document):
|
||||||
|
in_list = ListField(GenericLazyReferenceField())
|
||||||
|
in_embedded = EmbeddedDocumentField(EmbeddedOcurrence)
|
||||||
|
direct = GenericLazyReferenceField()
|
||||||
|
|
||||||
|
Animal.drop_collection()
|
||||||
|
Ocurrence.drop_collection()
|
||||||
|
|
||||||
|
animal1 = Animal('doggo').save()
|
||||||
|
animal2 = Animal('cheeta').save()
|
||||||
|
|
||||||
|
def check_fields_type(occ):
|
||||||
|
self.assertIsInstance(occ.direct, LazyReference)
|
||||||
|
for elem in occ.in_list:
|
||||||
|
self.assertIsInstance(elem, LazyReference)
|
||||||
|
self.assertIsInstance(occ.in_embedded.direct, LazyReference)
|
||||||
|
for elem in occ.in_embedded.in_list:
|
||||||
|
self.assertIsInstance(elem, LazyReference)
|
||||||
|
|
||||||
|
occ = Ocurrence(
|
||||||
|
in_list=[animal1, animal2],
|
||||||
|
in_embedded={'in_list': [animal1, animal2], 'direct': animal1},
|
||||||
|
direct=animal1
|
||||||
|
).save()
|
||||||
|
check_fields_type(occ)
|
||||||
|
occ.reload()
|
||||||
|
check_fields_type(occ)
|
||||||
|
animal1_ref = {'_cls': 'Animal', '_ref': DBRef(animal1._get_collection_name(), animal1.pk)}
|
||||||
|
animal2_ref = {'_cls': 'Animal', '_ref': DBRef(animal2._get_collection_name(), animal2.pk)}
|
||||||
|
occ.direct = animal1_ref
|
||||||
|
occ.in_list = [animal1_ref, animal2_ref]
|
||||||
|
occ.in_embedded.direct = animal1_ref
|
||||||
|
occ.in_embedded.in_list = [animal1_ref, animal2_ref]
|
||||||
|
check_fields_type(occ)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@@ -1929,6 +1929,21 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
post.reload()
|
post.reload()
|
||||||
self.assertEqual(post.tags, ['scala', 'mongodb', 'python', 'java'])
|
self.assertEqual(post.tags, ['scala', 'mongodb', 'python', 'java'])
|
||||||
|
|
||||||
|
def test_update_push_list_of_list(self):
|
||||||
|
"""Ensure that the 'push' update operation works in the list of list
|
||||||
|
"""
|
||||||
|
class BlogPost(Document):
|
||||||
|
slug = StringField()
|
||||||
|
tags = ListField()
|
||||||
|
|
||||||
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
|
post = BlogPost(slug="test").save()
|
||||||
|
|
||||||
|
BlogPost.objects.filter(slug="test").update(push__tags=["value1", 123])
|
||||||
|
post.reload()
|
||||||
|
self.assertEqual(post.tags, [["value1", 123]])
|
||||||
|
|
||||||
def test_update_push_and_pull_add_to_set(self):
|
def test_update_push_and_pull_add_to_set(self):
|
||||||
"""Ensure that the 'pull' update operation works correctly.
|
"""Ensure that the 'pull' update operation works correctly.
|
||||||
"""
|
"""
|
||||||
@@ -2071,6 +2086,23 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
Site.objects(id=s.id).update_one(
|
Site.objects(id=s.id).update_one(
|
||||||
pull_all__collaborators__helpful__user=['Ross'])
|
pull_all__collaborators__helpful__user=['Ross'])
|
||||||
|
|
||||||
|
def test_pull_in_genericembedded_field(self):
|
||||||
|
|
||||||
|
class Foo(EmbeddedDocument):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
class Bar(Document):
|
||||||
|
foos = ListField(GenericEmbeddedDocumentField(
|
||||||
|
choices=[Foo, ]))
|
||||||
|
|
||||||
|
Bar.drop_collection()
|
||||||
|
|
||||||
|
foo = Foo(name="bar")
|
||||||
|
bar = Bar(foos=[foo]).save()
|
||||||
|
Bar.objects(id=bar.id).update(pull__foos=foo)
|
||||||
|
bar.reload()
|
||||||
|
self.assertEqual(len(bar.foos), 0)
|
||||||
|
|
||||||
def test_update_one_pop_generic_reference(self):
|
def test_update_one_pop_generic_reference(self):
|
||||||
|
|
||||||
class BlogTag(Document):
|
class BlogTag(Document):
|
||||||
@@ -2164,6 +2196,24 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
self.assertEqual(message.authors[1].name, "Ross")
|
self.assertEqual(message.authors[1].name, "Ross")
|
||||||
self.assertEqual(message.authors[2].name, "Adam")
|
self.assertEqual(message.authors[2].name, "Adam")
|
||||||
|
|
||||||
|
def test_set_generic_embedded_documents(self):
|
||||||
|
|
||||||
|
class Bar(EmbeddedDocument):
|
||||||
|
name = StringField()
|
||||||
|
|
||||||
|
class User(Document):
|
||||||
|
username = StringField()
|
||||||
|
bar = GenericEmbeddedDocumentField(choices=[Bar,])
|
||||||
|
|
||||||
|
User.drop_collection()
|
||||||
|
|
||||||
|
User(username='abc').save()
|
||||||
|
User.objects(username='abc').update(
|
||||||
|
set__bar=Bar(name='test'), upsert=True)
|
||||||
|
|
||||||
|
user = User.objects(username='abc').first()
|
||||||
|
self.assertEqual(user.bar.name, "test")
|
||||||
|
|
||||||
def test_reload_embedded_docs_instance(self):
|
def test_reload_embedded_docs_instance(self):
|
||||||
|
|
||||||
class SubDoc(EmbeddedDocument):
|
class SubDoc(EmbeddedDocument):
|
||||||
@@ -4790,6 +4840,30 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
for obj in C.objects.no_sub_classes():
|
for obj in C.objects.no_sub_classes():
|
||||||
self.assertEqual(obj.__class__, C)
|
self.assertEqual(obj.__class__, C)
|
||||||
|
|
||||||
|
def test_query_generic_embedded_document(self):
|
||||||
|
"""Ensure that querying sub field on generic_embedded_field works
|
||||||
|
"""
|
||||||
|
class A(EmbeddedDocument):
|
||||||
|
a_name = StringField()
|
||||||
|
|
||||||
|
class B(EmbeddedDocument):
|
||||||
|
b_name = StringField()
|
||||||
|
|
||||||
|
class Doc(Document):
|
||||||
|
document = GenericEmbeddedDocumentField(choices=(A, B))
|
||||||
|
|
||||||
|
Doc.drop_collection()
|
||||||
|
Doc(document=A(a_name='A doc')).save()
|
||||||
|
Doc(document=B(b_name='B doc')).save()
|
||||||
|
|
||||||
|
# Using raw in filter working fine
|
||||||
|
self.assertEqual(Doc.objects(
|
||||||
|
__raw__={'document.a_name': 'A doc'}).count(), 1)
|
||||||
|
self.assertEqual(Doc.objects(
|
||||||
|
__raw__={'document.b_name': 'B doc'}).count(), 1)
|
||||||
|
self.assertEqual(Doc.objects(document__a_name='A doc').count(), 1)
|
||||||
|
self.assertEqual(Doc.objects(document__b_name='B doc').count(), 1)
|
||||||
|
|
||||||
def test_query_reference_to_custom_pk_doc(self):
|
def test_query_reference_to_custom_pk_doc(self):
|
||||||
|
|
||||||
class A(Document):
|
class A(Document):
|
||||||
|
Reference in New Issue
Block a user