Merge remote branch 'hmarr/master'
Conflicts: mongoengine/queryset.py
This commit is contained in:
commit
963a223e7e
@ -86,6 +86,41 @@ achieving this is using array-slicing syntax::
|
|||||||
# 5 users, starting from the 10th user found
|
# 5 users, starting from the 10th user found
|
||||||
users = User.objects[10:15]
|
users = User.objects[10:15]
|
||||||
|
|
||||||
|
You may also index the query to retrieve a single result. If an item at that
|
||||||
|
index does not exists, an :class:`IndexError` will be raised. A shortcut for
|
||||||
|
retrieving the first result and returning :attr:`None` if no result exists is
|
||||||
|
provided (:meth:`~mongoengine.queryset.QuerySet.first`)::
|
||||||
|
|
||||||
|
>>> # Make sure there are no users
|
||||||
|
>>> User.drop_collection()
|
||||||
|
>>> User.objects[0]
|
||||||
|
IndexError: list index out of range
|
||||||
|
>>> User.objects.first() == None
|
||||||
|
True
|
||||||
|
>>> User(name='Test User').save()
|
||||||
|
>>> User.objects[0] == User.objects.first()
|
||||||
|
True
|
||||||
|
|
||||||
|
Retrieving unique results
|
||||||
|
-------------------------
|
||||||
|
To retrieve a result that should be unique in the collection, use
|
||||||
|
:meth:`~mongoengine.queryset.QuerySet.get`. This will raise
|
||||||
|
:class:`~mongoengine.queryset.DoesNotExist` if no document matches the query,
|
||||||
|
and :class:`~mongoengine.queryset.MultipleObjectsReturned` if more than one
|
||||||
|
document matched the query.
|
||||||
|
|
||||||
|
A variation of this method exists,
|
||||||
|
:meth:`~mongoengine.queryset.Queryset.get_or_create`, that will create a new
|
||||||
|
document with the query arguments if no documents match the query. An
|
||||||
|
additional keyword argument, :attr:`defaults` may be provided, which will be
|
||||||
|
used as default values for the new document, in the case that it should need
|
||||||
|
to be created::
|
||||||
|
|
||||||
|
>>> a = User.objects.get_or_create(name='User A', defaults={'age': 30})
|
||||||
|
>>> b = User.objects.get_or_create(name='User A', defaults={'age': 40})
|
||||||
|
>>> a.name == b.name and a.age == b.age
|
||||||
|
True
|
||||||
|
|
||||||
Default Document queries
|
Default Document queries
|
||||||
========================
|
========================
|
||||||
By default, the objects :attr:`~mongoengine.Document.objects` attribute on a
|
By default, the objects :attr:`~mongoengine.Document.objects` attribute on a
|
||||||
|
@ -11,6 +11,11 @@ MongoDB. To install it, simply run
|
|||||||
|
|
||||||
The source is available on `GitHub <http://github.com/hmarr/mongoengine>`_.
|
The source is available on `GitHub <http://github.com/hmarr/mongoengine>`_.
|
||||||
|
|
||||||
|
If you are interested in contributing, join the developers' `mailing list
|
||||||
|
<http://groups.google.com/group/mongoengine-dev>`_. Some of us also like to
|
||||||
|
hang out at `#mongoengine IRC channel <irc://irc.freenode.net/mongoengine>`_.
|
||||||
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
@ -352,19 +352,15 @@ class BaseDocument(object):
|
|||||||
if value is not None:
|
if value is not None:
|
||||||
data[field.name] = field.to_mongo(value)
|
data[field.name] = field.to_mongo(value)
|
||||||
# Only add _cls and _types if allow_inheritance is not False
|
# Only add _cls and _types if allow_inheritance is not False
|
||||||
#if not (hasattr(self, '_meta') and
|
if not (hasattr(self, '_meta') and
|
||||||
# self._meta.get('allow_inheritance', True) == False):
|
self._meta.get('allow_inheritance', True) == False):
|
||||||
ah = True
|
|
||||||
if hasattr(self, '_meta'):
|
|
||||||
ah = self._meta.get('allow_inheritance', True)
|
|
||||||
if ah:
|
|
||||||
data['_cls'] = self._class_name
|
data['_cls'] = self._class_name
|
||||||
data['_types'] = self._superclasses.keys() + [self._class_name]
|
data['_types'] = self._superclasses.keys() + [self._class_name]
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _from_son(cls, son):
|
def _from_son(cls, son):
|
||||||
"""Create an instance of a Document (subclass) from a PyMongo SOM.
|
"""Create an instance of a Document (subclass) from a PyMongo SON.
|
||||||
"""
|
"""
|
||||||
# get the class name from the document, falling back to the given
|
# get the class name from the document, falling back to the given
|
||||||
# class if unavailable
|
# class if unavailable
|
||||||
|
@ -10,6 +10,7 @@ __all__ = ['queryset_manager', 'Q', 'InvalidQueryError',
|
|||||||
# The maximum number of items to display in a QuerySet.__repr__
|
# The maximum number of items to display in a QuerySet.__repr__
|
||||||
REPR_OUTPUT_SIZE = 20
|
REPR_OUTPUT_SIZE = 20
|
||||||
|
|
||||||
|
|
||||||
class DoesNotExist(Exception):
|
class DoesNotExist(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -299,37 +300,46 @@ class QuerySet(object):
|
|||||||
|
|
||||||
return mongo_query
|
return mongo_query
|
||||||
|
|
||||||
def get_or_create(self, **kwargs):
|
def get(self, *q_objs, **query):
|
||||||
"""Retreive unique object or create, if it doesn't exist
|
"""Retrieve the the matching object raising
|
||||||
|
:class:`~mongoengine.queryset.MultipleObjectsReturned` or
|
||||||
|
:class:`~mongoengine.queryset.DoesNotExist` exceptions if multiple or
|
||||||
|
no results are found.
|
||||||
"""
|
"""
|
||||||
defaults = kwargs.get('defaults', {})
|
self.__call__(*q_objs, **query)
|
||||||
if kwargs.has_key('defaults'):
|
count = self.count()
|
||||||
del kwargs['defaults']
|
if count == 1:
|
||||||
|
return self[0]
|
||||||
dataset = self.filter(**kwargs)
|
elif count > 1:
|
||||||
cnt = dataset.count()
|
message = u'%d items returned, instead of 1' % count
|
||||||
if cnt == 0:
|
raise MultipleObjectsReturned(message)
|
||||||
kwargs.update(defaults)
|
|
||||||
doc = self._document(**kwargs)
|
|
||||||
doc.save()
|
|
||||||
return doc
|
|
||||||
elif cnt == 1:
|
|
||||||
return dataset.first()
|
|
||||||
else:
|
|
||||||
raise MultipleObjectsReturned(u'%d items returned, expected exactly one' % cnt)
|
|
||||||
|
|
||||||
def get(self, **kwargs):
|
|
||||||
"""Retreive exactly one document. Raise DoesNotExist if it's not found.
|
|
||||||
"""
|
|
||||||
dataset = self.filter(**kwargs)
|
|
||||||
cnt = dataset.count()
|
|
||||||
if cnt == 1:
|
|
||||||
return dataset.first()
|
|
||||||
elif cnt > 1:
|
|
||||||
raise MultipleObjectsReturned(u'%d items returned, expected exactly one' % cnt)
|
|
||||||
else:
|
else:
|
||||||
raise DoesNotExist('Document not found')
|
raise DoesNotExist('Document not found')
|
||||||
|
|
||||||
|
def get_or_create(self, *q_objs, **query):
|
||||||
|
"""Retreive unique object or create, if it doesn't exist. Raises
|
||||||
|
:class:`~mongoengine.queryset.MultipleObjectsReturned` if multiple
|
||||||
|
results are found. A new document will be created if the document
|
||||||
|
doesn't exists; a dictionary of default values for the new document
|
||||||
|
may be provided as a keyword argument called :attr:`defaults`.
|
||||||
|
"""
|
||||||
|
defaults = query.get('defaults', {})
|
||||||
|
if query.has_key('defaults'):
|
||||||
|
del query['defaults']
|
||||||
|
|
||||||
|
self.__call__(*q_objs, **query)
|
||||||
|
count = self.count()
|
||||||
|
if count == 0:
|
||||||
|
query.update(defaults)
|
||||||
|
doc = self._document(**query)
|
||||||
|
doc.save()
|
||||||
|
return doc
|
||||||
|
elif count == 1:
|
||||||
|
return self.first()
|
||||||
|
else:
|
||||||
|
message = u'%d items returned, instead of 1' % count
|
||||||
|
raise MultipleObjectsReturned(message)
|
||||||
|
|
||||||
def first(self):
|
def first(self):
|
||||||
"""Retrieve the first object matching the query.
|
"""Retrieve the first object matching the query.
|
||||||
"""
|
"""
|
||||||
|
@ -2,7 +2,8 @@ import unittest
|
|||||||
import pymongo
|
import pymongo
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from mongoengine.queryset import QuerySet
|
from mongoengine.queryset import (QuerySet, MultipleObjectsReturned,
|
||||||
|
DoesNotExist)
|
||||||
from mongoengine import *
|
from mongoengine import *
|
||||||
|
|
||||||
|
|
||||||
@ -135,6 +136,54 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
person = self.Person.objects.with_id(person1.id)
|
person = self.Person.objects.with_id(person1.id)
|
||||||
self.assertEqual(person.name, "User A")
|
self.assertEqual(person.name, "User A")
|
||||||
|
|
||||||
|
def test_find_only_one(self):
|
||||||
|
"""Ensure that a query using ``get`` returns at most one result.
|
||||||
|
"""
|
||||||
|
# Try retrieving when no objects exists
|
||||||
|
self.assertRaises(DoesNotExist, self.Person.objects.get)
|
||||||
|
|
||||||
|
person1 = self.Person(name="User A", age=20)
|
||||||
|
person1.save()
|
||||||
|
person2 = self.Person(name="User B", age=30)
|
||||||
|
person2.save()
|
||||||
|
|
||||||
|
# Retrieve the first person from the database
|
||||||
|
self.assertRaises(MultipleObjectsReturned, self.Person.objects.get)
|
||||||
|
|
||||||
|
# Use a query to filter the people found to just person2
|
||||||
|
person = self.Person.objects.get(age=30)
|
||||||
|
self.assertEqual(person.name, "User B")
|
||||||
|
|
||||||
|
person = self.Person.objects.get(age__lt=30)
|
||||||
|
self.assertEqual(person.name, "User A")
|
||||||
|
|
||||||
|
def test_get_or_create(self):
|
||||||
|
"""Ensure that ``get_or_create`` returns one result or creates a new
|
||||||
|
document.
|
||||||
|
"""
|
||||||
|
person1 = self.Person(name="User A", age=20)
|
||||||
|
person1.save()
|
||||||
|
person2 = self.Person(name="User B", age=30)
|
||||||
|
person2.save()
|
||||||
|
|
||||||
|
# Retrieve the first person from the database
|
||||||
|
self.assertRaises(MultipleObjectsReturned,
|
||||||
|
self.Person.objects.get_or_create)
|
||||||
|
|
||||||
|
# Use a query to filter the people found to just person2
|
||||||
|
person = self.Person.objects.get_or_create(age=30)
|
||||||
|
self.assertEqual(person.name, "User B")
|
||||||
|
|
||||||
|
person = self.Person.objects.get_or_create(age__lt=30)
|
||||||
|
self.assertEqual(person.name, "User A")
|
||||||
|
|
||||||
|
# Try retrieving when no objects exists - new doc should be created
|
||||||
|
self.Person.objects.get_or_create(age=50, defaults={'name': 'User C'})
|
||||||
|
|
||||||
|
person = self.Person.objects.get(age=50)
|
||||||
|
self.assertEqual(person.name, "User C")
|
||||||
|
|
||||||
|
|
||||||
def test_filter_chaining(self):
|
def test_filter_chaining(self):
|
||||||
"""Ensure filters can be chained together.
|
"""Ensure filters can be chained together.
|
||||||
"""
|
"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user