Merge pull request #1167 from BeardedSteve/upsert_one

Upsert one
This commit is contained in:
Omer Katz 2015-11-30 12:08:04 +02:00
commit bf6f4c48c0
5 changed files with 40 additions and 3 deletions

View File

@ -231,3 +231,4 @@ that much better:
* Lars Butler (https://github.com/larsbutler) * Lars Butler (https://github.com/larsbutler)
* George Macon (https://github.com/gmacon) * George Macon (https://github.com/gmacon)
* Ashley Whetter (https://github.com/AWhetter) * Ashley Whetter (https://github.com/AWhetter)
* Steven Rossiter (https://github.com/BeardedSteve)

View File

@ -5,6 +5,7 @@ Changelog
Changes in 0.10.4 - DEV Changes in 0.10.4 - DEV
======================= =======================
- SaveConditionError is now importable from the top level package. #1165 - SaveConditionError is now importable from the top level package. #1165
- upsert_one method added. #1157
Changes in 0.10.3 Changes in 0.10.3
================= =================

View File

@ -14,7 +14,7 @@ import errors
__all__ = (list(document.__all__) + fields.__all__ + connection.__all__ + __all__ = (list(document.__all__) + fields.__all__ + connection.__all__ +
list(queryset.__all__) + signals.__all__ + list(errors.__all__)) list(queryset.__all__) + signals.__all__ + list(errors.__all__))
VERSION = (0, 10, 1) VERSION = (0, 10, 4)
def get_version(): def get_version():

View File

@ -471,6 +471,32 @@ class BaseQuerySet(object):
raise OperationError(message) raise OperationError(message)
raise OperationError(u'Update failed (%s)' % unicode(err)) raise OperationError(u'Update failed (%s)' % unicode(err))
def upsert_one(self, write_concern=None, **update):
"""Overwrite or add the first document matched by the query.
:param write_concern: Extra keyword arguments are passed down which
will be used as options for the resultant
``getLastError`` command. For example,
``save(..., write_concern={w: 2, fsync: True}, ...)`` will
wait until at least two servers have recorded the write and
will force an fsync on the primary server.
:param update: Django-style update keyword arguments
:returns the new or overwritten document
.. versionadded:: 0.10.2
"""
atomic_update = self.update(multi=False, upsert=True, write_concern=write_concern,
full_result=True,**update)
if atomic_update['updatedExisting']:
document = self.get()
else:
document = self._document.objects.with_id(atomic_update['upserted'])
return document
def update_one(self, upsert=False, write_concern=None, **update): def update_one(self, upsert=False, write_concern=None, **update):
"""Perform an atomic update on the fields of the first document """Perform an atomic update on the fields of the first document
matched by the query. matched by the query.

View File

@ -680,12 +680,21 @@ class QuerySetTest(unittest.TestCase):
def test_upsert_one(self): def test_upsert_one(self):
self.Person.drop_collection() self.Person.drop_collection()
self.Person.objects(name="Bob", age=30).update_one(upsert=True) bob = self.Person.objects(name="Bob", age=30).upsert_one()
bob = self.Person.objects.first()
self.assertEqual("Bob", bob.name) self.assertEqual("Bob", bob.name)
self.assertEqual(30, bob.age) self.assertEqual(30, bob.age)
bob.name = "Bobby"
bob.save()
bobby = self.Person.objects(name="Bobby", age=30).upsert_one()
self.assertEqual("Bobby", bobby.name)
self.assertEqual(30, bobby.age)
self.assertEqual(bob.id, bobby.id)
def test_set_on_insert(self): def test_set_on_insert(self):
self.Person.drop_collection() self.Person.drop_collection()