Compare commits

..

5 Commits

Author SHA1 Message Date
Stefan Wojcik
af292b0ec2 Bump version to v0.18.2 2019-06-25 16:52:31 +02:00
Stefan Wojcik
1ead7f9b2b Add changelog entries for v0.18.2 2019-06-25 16:51:56 +02:00
Stefan Wojcik
5c91877b69 Fix the Travis deployment condition
See https://github.com/MongoEngine/mongoengine/issues/2104 for details.

For now I'm hardcoding `$MONGODB = 3.4.17` just to get a release out there,
but we should probably use the globals going forward. Will do that in
a follow-up commit once I get the `travis-conditions` gem up and running and
hence can test `.travis.yml` changes without deploying.
2019-06-25 16:48:51 +02:00
Bastien Gérard
b1002dd4f9 Merge pull request #2097 from bagerard/remove_deprecated_pymongo_methods
remove pymongo deprecated methods: find_and_modify & remove
2019-06-24 22:03:58 +02:00
Bastien Gérard
8f57279dc7 remove pymongo deprecated methods: find_and_modify & remove 2019-06-19 23:04:23 +02:00
8 changed files with 34 additions and 118 deletions

View File

@@ -102,5 +102,5 @@ deploy:
on:
tags: true
repo: MongoEngine/mongoengine
condition: ($PYMONGO = 3.x) && ($MONGODB = 3.4)
condition: ($PYMONGO = 3.x) && ($MONGODB = 3.4.17)
python: 2.7

View File

@@ -6,7 +6,11 @@ Changelog
Development
===========
- (Fill this out as you fix issues and develop your features).
- Add a `BaseDocument.to_dict` method #2101
Changes in 0.18.2
=================
- Replace some of the deprecated PyMongo v2.x methods with their v3.x equivalents #2097
- Various code clarity and documentation improvements
Changes in 0.18.1
=================

View File

@@ -23,7 +23,7 @@ __all__ = (list(document.__all__) + list(fields.__all__) +
list(signals.__all__) + list(errors.__all__))
VERSION = (0, 18, 1)
VERSION = (0, 18, 2)
def get_version():

View File

@@ -309,7 +309,9 @@ class BaseDocument(object):
return self._data['_text_score']
def to_mongo(self, use_db_field=True, fields=None):
"""Return as SON data ready for use with MongoDB."""
"""
Return as SON data ready for use with MongoDB.
"""
fields = fields or []
data = SON()
@@ -410,35 +412,12 @@ class BaseDocument(object):
message = 'ValidationError (%s:%s) ' % (self._class_name, pk)
raise ValidationError(message, errors=errors)
def to_dict(self):
"""Serialize this document into a dict.
Return field names as they're defined on the document (as opposed to
e.g. how they're stored in MongoDB). Return values in their
deserialized form (i.e. the same form that you get when you access
`doc.some_field_name`). Serialize embedded documents recursively.
The resultant dict can be consumed easily by other modules which
don't need to be aware of MongoEngine-specific object types.
:return dict: dictionary of field name & value pairs.
"""
data_dict = {}
for field_name in self._fields:
value = getattr(self, field_name)
if isinstance(value, BaseDocument):
data_dict[field_name] = value.to_dict()
else:
data_dict[field_name] = value
return data_dict
def to_json(self, *args, **kwargs):
"""Convert this document to JSON.
:param use_db_field: Serialize field names as they appear in
MongoDB (as opposed to attribute names on this document).
Defaults to True.
:return str: string representing the jsonified document.
"""
use_db_field = kwargs.pop('use_db_field', True)
return json_util.dumps(self.to_mongo(use_db_field), *args, **kwargs)
@@ -447,13 +426,12 @@ class BaseDocument(object):
def from_json(cls, json_data, created=False):
"""Converts json data to a Document instance
:param str json_data: The json data to load into the Document
:param bool created: If True, the document will be considered as
a brand new document. If False and an ID is provided, it will
consider that the data being loaded corresponds to what's already
in the database (This has an impact of subsequent call to .save())
If False and no id is provided, it will consider the data as a new
document (default ``False``)
:param json_data: The json data to load into the Document
:param created: If True, the document will be considered as a brand new document
If False and an id is provided, it will consider that the data being
loaded corresponds to what's already in the database (This has an impact of subsequent call to .save())
If False and no id is provided, it will consider the data as a new document
(default ``False``)
"""
return cls._from_son(json_util.loads(json_data), created=created)

View File

@@ -10,6 +10,7 @@ from operator import itemgetter
from bson import Binary, DBRef, ObjectId, SON
import gridfs
import pymongo
from pymongo import ReturnDocument
import six
from six import iteritems
@@ -1964,10 +1965,12 @@ class SequenceField(BaseField):
sequence_name = self.get_sequence_name()
sequence_id = '%s.%s' % (sequence_name, self.name)
collection = get_db(alias=self.db_alias)[self.collection_name]
counter = collection.find_and_modify(query={'_id': sequence_id},
update={'$inc': {'next': 1}},
new=True,
upsert=True)
counter = collection.find_one_and_update(
filter={'_id': sequence_id},
update={'$inc': {'next': 1}},
return_document=ReturnDocument.AFTER,
upsert=True)
return self.value_decorator(counter['next'])
def set_next_value(self, value):
@@ -1975,10 +1978,11 @@ class SequenceField(BaseField):
sequence_name = self.get_sequence_name()
sequence_id = "%s.%s" % (sequence_name, self.name)
collection = get_db(alias=self.db_alias)[self.collection_name]
counter = collection.find_and_modify(query={"_id": sequence_id},
update={"$set": {"next": value}},
new=True,
upsert=True)
counter = collection.find_one_and_update(
filter={"_id": sequence_id},
update={"$set": {"next": value}},
return_document=ReturnDocument.AFTER,
upsert=True)
return self.value_decorator(counter['next'])
def get_next_value(self):

View File

@@ -481,9 +481,10 @@ class BaseQuerySet(object):
write_concern=write_concern,
**{'pull_all__%s' % field_name: self})
result = queryset._collection.remove(queryset._query, **write_concern)
if result:
return result.get('n')
with set_write_concern(queryset._collection, write_concern) as collection:
result = collection.delete_many(queryset._query)
if result.acknowledged:
return result.deleted_count
def update(self, upsert=False, multi=True, write_concern=None,
full_result=False, **update):

View File

@@ -3525,76 +3525,5 @@ class InstanceTest(MongoDBTestCase):
User.objects().select_related()
class DocumentToDictTest(MongoDBTestCase):
"""Class for testing the BaseDocument.to_dict method."""
def test_to_dict(self):
class Person(Document):
name = StringField()
age = IntField()
p = Person(name='Tom', age=30)
self.assertEqual(p.to_dict(), {'id': None, 'name': 'Tom', 'age': 30})
def test_to_dict_with_a_persisted_doc(self):
class Person(Document):
name = StringField()
age = IntField()
p = Person.objects.create(name='Tom', age=30)
p_dict = p.to_dict()
self.assertTrue(p_dict['id'])
self.assertEqual(p_dict['name'], 'Tom')
self.assertEqual(p_dict['age'], 30)
def test_to_dict_empty_doc(self):
class Person(Document):
name = StringField()
age = IntField()
p = Person()
self.assertEqual(p.to_dict(), {'id': None, 'name': None, 'age': None})
def test_to_dict_with_default_values(self):
class Person(Document):
name = StringField(default='Unknown')
age = IntField(default=0)
p = Person()
self.assertEqual(
p.to_dict(),
{'id': None, 'name': 'Unknown', 'age': 0}
)
def test_to_dict_with_a_db_field(self):
class Person(Document):
name = StringField(db_field='db_name')
p = Person(name='Tom')
self.assertEqual(p.to_dict(), {'id': None, 'name': 'Tom'})
def test_to_dict_with_a_primary_key(self):
class Person(Document):
username = StringField(primary_key=True)
p = Person(username='tomtom')
self.assertEqual(p.to_dict(), {'username': 'tomtom'})
def test_to_dict_with_an_embedded_document(self):
class Book(EmbeddedDocument):
title = StringField()
class Author(Document):
name = StringField()
book = EmbeddedDocumentField(Book)
a = Author(name='Yuval', book=Book(title='Sapiens'))
self.assertEqual(a.to_dict(), {
'id': None,
'name': 'Yuval',
'book': {'title': 'Sapiens'}
})
if __name__ == '__main__':
unittest.main()

View File

@@ -1857,8 +1857,8 @@ class QuerySetTest(unittest.TestCase):
self.Person.objects()[:1].delete()
self.assertEqual(1, BlogPost.objects.count())
def test_limit_with_write_concern_0(self):
def test_delete_edge_case_with_write_concern_0_return_None(self):
"""Return None when write is unacknowledged"""
p1 = self.Person(name="User Z", age=20).save()
del_result = p1.delete(w=0)
self.assertEqual(None, del_result)