Merge branch 'master' into remove-pushall
This commit is contained in:
commit
72c4444a60
3
AUTHORS
3
AUTHORS
@ -244,4 +244,5 @@ that much better:
|
|||||||
* Stanislav Kaledin (https://github.com/sallyruthstruik)
|
* Stanislav Kaledin (https://github.com/sallyruthstruik)
|
||||||
* Dmitry Yantsen (https://github.com/mrTable)
|
* Dmitry Yantsen (https://github.com/mrTable)
|
||||||
* Renjianxin (https://github.com/Davidrjx)
|
* Renjianxin (https://github.com/Davidrjx)
|
||||||
* Erdenezul Batmunkh (https://github.com/erdenezul)
|
* Erdenezul Batmunkh (https://github.com/erdenezul)
|
||||||
|
* Andy Yankovsky (https://github.com/werat)
|
||||||
|
@ -87,7 +87,9 @@ Fields
|
|||||||
.. autoclass:: mongoengine.fields.DictField
|
.. autoclass:: mongoengine.fields.DictField
|
||||||
.. autoclass:: mongoengine.fields.MapField
|
.. autoclass:: mongoengine.fields.MapField
|
||||||
.. autoclass:: mongoengine.fields.ReferenceField
|
.. autoclass:: mongoengine.fields.ReferenceField
|
||||||
|
.. autoclass:: mongoengine.fields.LazyReferenceField
|
||||||
.. autoclass:: mongoengine.fields.GenericReferenceField
|
.. autoclass:: mongoengine.fields.GenericReferenceField
|
||||||
|
.. autoclass:: mongoengine.fields.GenericLazyReferenceField
|
||||||
.. autoclass:: mongoengine.fields.CachedReferenceField
|
.. autoclass:: mongoengine.fields.CachedReferenceField
|
||||||
.. autoclass:: mongoengine.fields.BinaryField
|
.. autoclass:: mongoengine.fields.BinaryField
|
||||||
.. autoclass:: mongoengine.fields.FileField
|
.. autoclass:: mongoengine.fields.FileField
|
||||||
|
@ -22,7 +22,7 @@ objects** as class attributes to the document class::
|
|||||||
|
|
||||||
class Page(Document):
|
class Page(Document):
|
||||||
title = StringField(max_length=200, required=True)
|
title = StringField(max_length=200, required=True)
|
||||||
date_modified = DateTimeField(default=datetime.datetime.now)
|
date_modified = DateTimeField(default=datetime.datetime.utcnow)
|
||||||
|
|
||||||
As BSON (the binary format for storing data in mongodb) is order dependent,
|
As BSON (the binary format for storing data in mongodb) is order dependent,
|
||||||
documents are serialized based on their field order.
|
documents are serialized based on their field order.
|
||||||
@ -80,6 +80,7 @@ are as follows:
|
|||||||
* :class:`~mongoengine.fields.FloatField`
|
* :class:`~mongoengine.fields.FloatField`
|
||||||
* :class:`~mongoengine.fields.GenericEmbeddedDocumentField`
|
* :class:`~mongoengine.fields.GenericEmbeddedDocumentField`
|
||||||
* :class:`~mongoengine.fields.GenericReferenceField`
|
* :class:`~mongoengine.fields.GenericReferenceField`
|
||||||
|
* :class:`~mongoengine.fields.GenericLazyReferenceField`
|
||||||
* :class:`~mongoengine.fields.GeoPointField`
|
* :class:`~mongoengine.fields.GeoPointField`
|
||||||
* :class:`~mongoengine.fields.ImageField`
|
* :class:`~mongoengine.fields.ImageField`
|
||||||
* :class:`~mongoengine.fields.IntField`
|
* :class:`~mongoengine.fields.IntField`
|
||||||
@ -87,6 +88,7 @@ are as follows:
|
|||||||
* :class:`~mongoengine.fields.MapField`
|
* :class:`~mongoengine.fields.MapField`
|
||||||
* :class:`~mongoengine.fields.ObjectIdField`
|
* :class:`~mongoengine.fields.ObjectIdField`
|
||||||
* :class:`~mongoengine.fields.ReferenceField`
|
* :class:`~mongoengine.fields.ReferenceField`
|
||||||
|
* :class:`~mongoengine.fields.LazyReferenceField`
|
||||||
* :class:`~mongoengine.fields.SequenceField`
|
* :class:`~mongoengine.fields.SequenceField`
|
||||||
* :class:`~mongoengine.fields.SortedListField`
|
* :class:`~mongoengine.fields.SortedListField`
|
||||||
* :class:`~mongoengine.fields.StringField`
|
* :class:`~mongoengine.fields.StringField`
|
||||||
@ -224,7 +226,7 @@ store; in this situation a :class:`~mongoengine.fields.DictField` is appropriate
|
|||||||
user = ReferenceField(User)
|
user = ReferenceField(User)
|
||||||
answers = DictField()
|
answers = DictField()
|
||||||
|
|
||||||
survey_response = SurveyResponse(date=datetime.now(), user=request.user)
|
survey_response = SurveyResponse(date=datetime.utcnow(), user=request.user)
|
||||||
response_form = ResponseForm(request.POST)
|
response_form = ResponseForm(request.POST)
|
||||||
survey_response.answers = response_form.cleaned_data()
|
survey_response.answers = response_form.cleaned_data()
|
||||||
survey_response.save()
|
survey_response.save()
|
||||||
@ -618,7 +620,7 @@ collection after a given period. See the official
|
|||||||
documentation for more information. A common usecase might be session data::
|
documentation for more information. A common usecase might be session data::
|
||||||
|
|
||||||
class Session(Document):
|
class Session(Document):
|
||||||
created = DateTimeField(default=datetime.now)
|
created = DateTimeField(default=datetime.utcnow)
|
||||||
meta = {
|
meta = {
|
||||||
'indexes': [
|
'indexes': [
|
||||||
{'fields': ['created'], 'expireAfterSeconds': 3600}
|
{'fields': ['created'], 'expireAfterSeconds': 3600}
|
||||||
|
@ -86,7 +86,7 @@ of them stand out as particularly intuitive solutions.
|
|||||||
Posts
|
Posts
|
||||||
^^^^^
|
^^^^^
|
||||||
|
|
||||||
Happily mongoDB *isn't* a relational database, so we're not going to do it that
|
Happily MongoDB *isn't* a relational database, so we're not going to do it that
|
||||||
way. As it turns out, we can use MongoDB's schemaless nature to provide us with
|
way. As it turns out, we can use MongoDB's schemaless nature to provide us with
|
||||||
a much nicer solution. We will store all of the posts in *one collection* and
|
a much nicer solution. We will store all of the posts in *one collection* and
|
||||||
each post type will only store the fields it needs. If we later want to add
|
each post type will only store the fields it needs. If we later want to add
|
||||||
|
@ -351,7 +351,8 @@ class EmbeddedDocumentList(BaseList):
|
|||||||
|
|
||||||
def update(self, **update):
|
def update(self, **update):
|
||||||
"""
|
"""
|
||||||
Updates the embedded documents with the given update values.
|
Updates the embedded documents with the given replacement values. This
|
||||||
|
function does not support mongoDB update operators such as ``inc__``.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
The embedded document changes are not automatically saved
|
The embedded document changes are not automatically saved
|
||||||
|
@ -280,6 +280,9 @@ class Document(BaseDocument):
|
|||||||
elif query[id_field] != self.pk:
|
elif query[id_field] != self.pk:
|
||||||
raise InvalidQueryError('Invalid document modify query: it must modify only this document.')
|
raise InvalidQueryError('Invalid document modify query: it must modify only this document.')
|
||||||
|
|
||||||
|
# Need to add shard key to query, or you get an error
|
||||||
|
query.update(self._object_key)
|
||||||
|
|
||||||
updated = self._qs(**query).modify(new=True, **update)
|
updated = self._qs(**query).modify(new=True, **update)
|
||||||
if updated is None:
|
if updated is None:
|
||||||
return False
|
return False
|
||||||
|
@ -614,6 +614,7 @@ class EmbeddedDocumentField(BaseField):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, document_type, **kwargs):
|
def __init__(self, document_type, **kwargs):
|
||||||
|
# XXX ValidationError raised outside of the "validate" method.
|
||||||
if not (
|
if not (
|
||||||
isinstance(document_type, six.string_types) or
|
isinstance(document_type, six.string_types) or
|
||||||
issubclass(document_type, EmbeddedDocument)
|
issubclass(document_type, EmbeddedDocument)
|
||||||
@ -919,8 +920,11 @@ class DictField(ComplexBaseField):
|
|||||||
self.field = field
|
self.field = field
|
||||||
self._auto_dereference = False
|
self._auto_dereference = False
|
||||||
self.basecls = basecls or BaseField
|
self.basecls = basecls or BaseField
|
||||||
|
|
||||||
|
# XXX ValidationError raised outside of the "validate" method.
|
||||||
if not issubclass(self.basecls, BaseField):
|
if not issubclass(self.basecls, BaseField):
|
||||||
self.error('DictField only accepts dict values')
|
self.error('DictField only accepts dict values')
|
||||||
|
|
||||||
kwargs.setdefault('default', lambda: {})
|
kwargs.setdefault('default', lambda: {})
|
||||||
super(DictField, self).__init__(*args, **kwargs)
|
super(DictField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
@ -969,6 +973,7 @@ class MapField(DictField):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, field=None, *args, **kwargs):
|
def __init__(self, field=None, *args, **kwargs):
|
||||||
|
# XXX ValidationError raised outside of the "validate" method.
|
||||||
if not isinstance(field, BaseField):
|
if not isinstance(field, BaseField):
|
||||||
self.error('Argument to MapField constructor must be a valid '
|
self.error('Argument to MapField constructor must be a valid '
|
||||||
'field')
|
'field')
|
||||||
@ -1028,6 +1033,7 @@ class ReferenceField(BaseField):
|
|||||||
A reference to an abstract document type is always stored as a
|
A reference to an abstract document type is always stored as a
|
||||||
:class:`~pymongo.dbref.DBRef`, regardless of the value of `dbref`.
|
:class:`~pymongo.dbref.DBRef`, regardless of the value of `dbref`.
|
||||||
"""
|
"""
|
||||||
|
# XXX ValidationError raised outside of the "validate" method.
|
||||||
if (
|
if (
|
||||||
not isinstance(document_type, six.string_types) and
|
not isinstance(document_type, six.string_types) and
|
||||||
not issubclass(document_type, Document)
|
not issubclass(document_type, Document)
|
||||||
@ -1082,6 +1088,8 @@ class ReferenceField(BaseField):
|
|||||||
if isinstance(document, Document):
|
if isinstance(document, Document):
|
||||||
# We need the id from the saved object to create the DBRef
|
# We need the id from the saved object to create the DBRef
|
||||||
id_ = document.pk
|
id_ = document.pk
|
||||||
|
|
||||||
|
# XXX ValidationError raised outside of the "validate" method.
|
||||||
if id_ is None:
|
if id_ is None:
|
||||||
self.error('You can only reference documents once they have'
|
self.error('You can only reference documents once they have'
|
||||||
' been saved to the database')
|
' been saved to the database')
|
||||||
@ -1121,7 +1129,6 @@ class ReferenceField(BaseField):
|
|||||||
return self.to_mongo(value)
|
return self.to_mongo(value)
|
||||||
|
|
||||||
def validate(self, value):
|
def validate(self, value):
|
||||||
|
|
||||||
if not isinstance(value, (self.document_type, LazyReference, DBRef, ObjectId)):
|
if not isinstance(value, (self.document_type, LazyReference, DBRef, ObjectId)):
|
||||||
self.error('A ReferenceField only accepts DBRef, LazyReference, ObjectId or documents')
|
self.error('A ReferenceField only accepts DBRef, LazyReference, ObjectId or documents')
|
||||||
|
|
||||||
@ -1129,11 +1136,14 @@ class ReferenceField(BaseField):
|
|||||||
self.error('You can only reference documents once they have been '
|
self.error('You can only reference documents once they have been '
|
||||||
'saved to the database')
|
'saved to the database')
|
||||||
|
|
||||||
if self.document_type._meta.get('abstract') and \
|
if (
|
||||||
not isinstance(value, self.document_type):
|
self.document_type._meta.get('abstract') and
|
||||||
|
not isinstance(value, self.document_type)
|
||||||
|
):
|
||||||
self.error(
|
self.error(
|
||||||
'%s is not an instance of abstract reference type %s' % (
|
'%s is not an instance of abstract reference type %s' % (
|
||||||
self.document_type._class_name)
|
self.document_type._class_name
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def lookup_member(self, member_name):
|
def lookup_member(self, member_name):
|
||||||
@ -1156,6 +1166,7 @@ class CachedReferenceField(BaseField):
|
|||||||
if fields is None:
|
if fields is None:
|
||||||
fields = []
|
fields = []
|
||||||
|
|
||||||
|
# XXX ValidationError raised outside of the "validate" method.
|
||||||
if (
|
if (
|
||||||
not isinstance(document_type, six.string_types) and
|
not isinstance(document_type, six.string_types) and
|
||||||
not issubclass(document_type, Document)
|
not issubclass(document_type, Document)
|
||||||
@ -1230,6 +1241,7 @@ class CachedReferenceField(BaseField):
|
|||||||
id_field_name = self.document_type._meta['id_field']
|
id_field_name = self.document_type._meta['id_field']
|
||||||
id_field = self.document_type._fields[id_field_name]
|
id_field = self.document_type._fields[id_field_name]
|
||||||
|
|
||||||
|
# XXX ValidationError raised outside of the "validate" method.
|
||||||
if isinstance(document, Document):
|
if isinstance(document, Document):
|
||||||
# We need the id from the saved object to create the DBRef
|
# We need the id from the saved object to create the DBRef
|
||||||
id_ = document.pk
|
id_ = document.pk
|
||||||
@ -1238,7 +1250,6 @@ class CachedReferenceField(BaseField):
|
|||||||
' been saved to the database')
|
' been saved to the database')
|
||||||
else:
|
else:
|
||||||
self.error('Only accept a document object')
|
self.error('Only accept a document object')
|
||||||
# TODO: should raise here or will fail next statement
|
|
||||||
|
|
||||||
value = SON((
|
value = SON((
|
||||||
('_id', id_field.to_mongo(id_)),
|
('_id', id_field.to_mongo(id_)),
|
||||||
@ -1256,6 +1267,7 @@ class CachedReferenceField(BaseField):
|
|||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# XXX ValidationError raised outside of the "validate" method.
|
||||||
if isinstance(value, Document):
|
if isinstance(value, Document):
|
||||||
if value.pk is None:
|
if value.pk is None:
|
||||||
self.error('You can only reference documents once they have'
|
self.error('You can only reference documents once they have'
|
||||||
@ -1269,7 +1281,6 @@ class CachedReferenceField(BaseField):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def validate(self, value):
|
def validate(self, value):
|
||||||
|
|
||||||
if not isinstance(value, self.document_type):
|
if not isinstance(value, self.document_type):
|
||||||
self.error('A CachedReferenceField only accepts documents')
|
self.error('A CachedReferenceField only accepts documents')
|
||||||
|
|
||||||
@ -1330,6 +1341,8 @@ class GenericReferenceField(BaseField):
|
|||||||
elif isinstance(choice, type) and issubclass(choice, Document):
|
elif isinstance(choice, type) and issubclass(choice, Document):
|
||||||
self.choices.append(choice._class_name)
|
self.choices.append(choice._class_name)
|
||||||
else:
|
else:
|
||||||
|
# XXX ValidationError raised outside of the "validate"
|
||||||
|
# method.
|
||||||
self.error('Invalid choices provided: must be a list of'
|
self.error('Invalid choices provided: must be a list of'
|
||||||
'Document subclasses and/or six.string_typess')
|
'Document subclasses and/or six.string_typess')
|
||||||
|
|
||||||
@ -1393,6 +1406,7 @@ class GenericReferenceField(BaseField):
|
|||||||
# We need the id from the saved object to create the DBRef
|
# We need the id from the saved object to create the DBRef
|
||||||
id_ = document.id
|
id_ = document.id
|
||||||
if id_ is None:
|
if id_ is None:
|
||||||
|
# XXX ValidationError raised outside of the "validate" method.
|
||||||
self.error('You can only reference documents once they have'
|
self.error('You can only reference documents once they have'
|
||||||
' been saved to the database')
|
' been saved to the database')
|
||||||
else:
|
else:
|
||||||
@ -2190,8 +2204,11 @@ class MultiPolygonField(GeoJsonBaseField):
|
|||||||
|
|
||||||
class LazyReferenceField(BaseField):
|
class LazyReferenceField(BaseField):
|
||||||
"""A really lazy reference to a document.
|
"""A really lazy reference to a document.
|
||||||
Unlike the :class:`~mongoengine.fields.ReferenceField` it must be manually
|
Unlike the :class:`~mongoengine.fields.ReferenceField` it will
|
||||||
dereferenced using it ``fetch()`` method.
|
**not** be automatically (lazily) dereferenced on access.
|
||||||
|
Instead, access will return a :class:`~mongoengine.base.LazyReference` class
|
||||||
|
instance, allowing access to `pk` or manual dereference by using
|
||||||
|
``fetch()`` method.
|
||||||
|
|
||||||
.. versionadded:: 0.15
|
.. versionadded:: 0.15
|
||||||
"""
|
"""
|
||||||
@ -2209,6 +2226,7 @@ class LazyReferenceField(BaseField):
|
|||||||
automatically call `fetch()` and try to retrive the field on the fetched
|
automatically call `fetch()` and try to retrive the field on the fetched
|
||||||
document. Note this only work getting field (not setting or deleting).
|
document. Note this only work getting field (not setting or deleting).
|
||||||
"""
|
"""
|
||||||
|
# XXX ValidationError raised outside of the "validate" method.
|
||||||
if (
|
if (
|
||||||
not isinstance(document_type, six.string_types) and
|
not isinstance(document_type, six.string_types) and
|
||||||
not issubclass(document_type, Document)
|
not issubclass(document_type, Document)
|
||||||
@ -2316,10 +2334,12 @@ class LazyReferenceField(BaseField):
|
|||||||
|
|
||||||
|
|
||||||
class GenericLazyReferenceField(GenericReferenceField):
|
class GenericLazyReferenceField(GenericReferenceField):
|
||||||
"""A reference to *any* :class:`~mongoengine.document.Document` subclass
|
"""A reference to *any* :class:`~mongoengine.document.Document` subclass.
|
||||||
that will be automatically dereferenced on access (lazily).
|
Unlike the :class:`~mongoengine.fields.GenericReferenceField` it will
|
||||||
Unlike the :class:`~mongoengine.fields.GenericReferenceField` it must be
|
**not** be automatically (lazily) dereferenced on access.
|
||||||
manually dereferenced using it ``fetch()`` method.
|
Instead, access will return a :class:`~mongoengine.base.LazyReference` class
|
||||||
|
instance, allowing access to `pk` or manual dereference by using
|
||||||
|
``fetch()`` method.
|
||||||
|
|
||||||
.. note ::
|
.. note ::
|
||||||
* Any documents used as a generic reference must be registered in the
|
* Any documents used as a generic reference must be registered in the
|
||||||
|
@ -486,8 +486,9 @@ class BaseQuerySet(object):
|
|||||||
``save(..., write_concern={w: 2, fsync: True}, ...)`` will
|
``save(..., write_concern={w: 2, fsync: True}, ...)`` will
|
||||||
wait until at least two servers have recorded the write and
|
wait until at least two servers have recorded the write and
|
||||||
will force an fsync on the primary server.
|
will force an fsync on the primary server.
|
||||||
:param full_result: Return the full result rather than just the number
|
:param full_result: Return the full result dictionary rather than just the number
|
||||||
updated.
|
updated, e.g. return
|
||||||
|
``{'n': 2, 'nModified': 2, 'ok': 1.0, 'updatedExisting': True}``.
|
||||||
:param update: Django-style update keyword arguments
|
:param update: Django-style update keyword arguments
|
||||||
|
|
||||||
.. versionadded:: 0.2
|
.. versionadded:: 0.2
|
||||||
|
@ -101,21 +101,8 @@ def query(_doc_cls=None, **kwargs):
|
|||||||
value = value['_id']
|
value = value['_id']
|
||||||
|
|
||||||
elif op in ('in', 'nin', 'all', 'near') and not isinstance(value, dict):
|
elif op in ('in', 'nin', 'all', 'near') and not isinstance(value, dict):
|
||||||
# Raise an error if the in/nin/all/near param is not iterable. We need a
|
# Raise an error if the in/nin/all/near param is not iterable.
|
||||||
# special check for BaseDocument, because - although it's iterable - using
|
value = _prepare_query_for_iterable(field, op, value)
|
||||||
# it as such in the context of this method is most definitely a mistake.
|
|
||||||
BaseDocument = _import_class('BaseDocument')
|
|
||||||
if isinstance(value, BaseDocument):
|
|
||||||
raise TypeError("When using the `in`, `nin`, `all`, or "
|
|
||||||
"`near`-operators you can\'t use a "
|
|
||||||
"`Document`, you must wrap your object "
|
|
||||||
"in a list (object -> [object]).")
|
|
||||||
elif not hasattr(value, '__iter__'):
|
|
||||||
raise TypeError("The `in`, `nin`, `all`, or "
|
|
||||||
"`near`-operators must be applied to an "
|
|
||||||
"iterable (e.g. a list).")
|
|
||||||
else:
|
|
||||||
value = [field.prepare_query_value(op, v) for v in value]
|
|
||||||
|
|
||||||
# If we're querying a GenericReferenceField, we need to alter the
|
# If we're querying a GenericReferenceField, we need to alter the
|
||||||
# key depending on the value:
|
# key depending on the value:
|
||||||
@ -284,9 +271,15 @@ def update(_doc_cls=None, **update):
|
|||||||
if isinstance(field, GeoJsonBaseField):
|
if isinstance(field, GeoJsonBaseField):
|
||||||
value = field.to_mongo(value)
|
value = field.to_mongo(value)
|
||||||
|
|
||||||
if op == 'push' and isinstance(value, (list, tuple, set)):
|
if op == 'pull':
|
||||||
|
if field.required or value is not None:
|
||||||
|
if match == 'in' and not isinstance(value, dict):
|
||||||
|
value = _prepare_query_for_iterable(field, op, value)
|
||||||
|
else:
|
||||||
|
value = field.prepare_query_value(op, value)
|
||||||
|
elif op == 'push' and isinstance(value, (list, tuple, set)):
|
||||||
value = [field.prepare_query_value(op, v) for v in value]
|
value = [field.prepare_query_value(op, v) for v in value]
|
||||||
elif op in (None, 'set', 'push', 'pull'):
|
elif op in (None, 'set', 'push'):
|
||||||
if field.required or value is not None:
|
if field.required or value is not None:
|
||||||
value = field.prepare_query_value(op, value)
|
value = field.prepare_query_value(op, value)
|
||||||
elif op in ('pushAll', 'pullAll'):
|
elif op in ('pushAll', 'pullAll'):
|
||||||
@ -443,3 +436,22 @@ def _infer_geometry(value):
|
|||||||
|
|
||||||
raise InvalidQueryError('Invalid $geometry data. Can be either a '
|
raise InvalidQueryError('Invalid $geometry data. Can be either a '
|
||||||
'dictionary or (nested) lists of coordinate(s)')
|
'dictionary or (nested) lists of coordinate(s)')
|
||||||
|
|
||||||
|
|
||||||
|
def _prepare_query_for_iterable(field, op, value):
|
||||||
|
# We need a special check for BaseDocument, because - although it's iterable - using
|
||||||
|
# it as such in the context of this method is most definitely a mistake.
|
||||||
|
BaseDocument = _import_class('BaseDocument')
|
||||||
|
|
||||||
|
if isinstance(value, BaseDocument):
|
||||||
|
raise TypeError("When using the `in`, `nin`, `all`, or "
|
||||||
|
"`near`-operators you can\'t use a "
|
||||||
|
"`Document`, you must wrap your object "
|
||||||
|
"in a list (object -> [object]).")
|
||||||
|
|
||||||
|
if not hasattr(value, '__iter__'):
|
||||||
|
raise TypeError("The `in`, `nin`, `all`, or "
|
||||||
|
"`near`-operators must be applied to an "
|
||||||
|
"iterable (e.g. a list).")
|
||||||
|
|
||||||
|
return [field.prepare_query_value(op, v) for v in value]
|
||||||
|
@ -1341,6 +1341,23 @@ class InstanceTest(unittest.TestCase):
|
|||||||
site = Site.objects.first()
|
site = Site.objects.first()
|
||||||
self.assertEqual(site.page.log_message, "Error: Dummy message")
|
self.assertEqual(site.page.log_message, "Error: Dummy message")
|
||||||
|
|
||||||
|
def test_update_list_field(self):
|
||||||
|
"""Test update on `ListField` with $pull + $in.
|
||||||
|
"""
|
||||||
|
class Doc(Document):
|
||||||
|
foo = ListField(StringField())
|
||||||
|
|
||||||
|
Doc.drop_collection()
|
||||||
|
doc = Doc(foo=['a', 'b', 'c'])
|
||||||
|
doc.save()
|
||||||
|
|
||||||
|
# Update
|
||||||
|
doc = Doc.objects.first()
|
||||||
|
doc.update(pull__foo__in=['a', 'c'])
|
||||||
|
|
||||||
|
doc = Doc.objects.first()
|
||||||
|
self.assertEqual(doc.foo, ['b'])
|
||||||
|
|
||||||
def test_embedded_update_db_field(self):
|
def test_embedded_update_db_field(self):
|
||||||
"""Test update on `EmbeddedDocumentField` fields when db_field
|
"""Test update on `EmbeddedDocumentField` fields when db_field
|
||||||
is other than default.
|
is other than default.
|
||||||
|
@ -28,12 +28,16 @@ class TransformTest(unittest.TestCase):
|
|||||||
{'name': {'$exists': True}})
|
{'name': {'$exists': True}})
|
||||||
|
|
||||||
def test_transform_update(self):
|
def test_transform_update(self):
|
||||||
|
class LisDoc(Document):
|
||||||
|
foo = ListField(StringField())
|
||||||
|
|
||||||
class DicDoc(Document):
|
class DicDoc(Document):
|
||||||
dictField = DictField()
|
dictField = DictField()
|
||||||
|
|
||||||
class Doc(Document):
|
class Doc(Document):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
LisDoc.drop_collection()
|
||||||
DicDoc.drop_collection()
|
DicDoc.drop_collection()
|
||||||
Doc.drop_collection()
|
Doc.drop_collection()
|
||||||
|
|
||||||
@ -50,6 +54,9 @@ class TransformTest(unittest.TestCase):
|
|||||||
|
|
||||||
update = transform.update(DicDoc, pull__dictField__test=doc)
|
update = transform.update(DicDoc, pull__dictField__test=doc)
|
||||||
self.assertTrue(isinstance(update["$pull"]["dictField"]["test"], dict))
|
self.assertTrue(isinstance(update["$pull"]["dictField"]["test"], dict))
|
||||||
|
|
||||||
|
update = transform.update(LisDoc, pull__foo__in=['a'])
|
||||||
|
self.assertEqual(update, {'$pull': {'foo': {'$in': ['a']}}})
|
||||||
|
|
||||||
def test_transform_update_push(self):
|
def test_transform_update_push(self):
|
||||||
"""Ensure the differences in behvaior between 'push' and 'push_all'"""
|
"""Ensure the differences in behvaior between 'push' and 'push_all'"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user