From c38faebc25a4a4bfa749d97005a43e6bbe6c0be3 Mon Sep 17 00:00:00 2001 From: James Punteney Date: Sat, 16 Jan 2010 13:21:16 -0500 Subject: [PATCH 1/3] Adding a get method to the queryset that raises exceptions if more or less than one item is returned --- mongoengine/queryset.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/mongoengine/queryset.py b/mongoengine/queryset.py index 06c82cf9..7d89a447 100644 --- a/mongoengine/queryset.py +++ b/mongoengine/queryset.py @@ -18,6 +18,11 @@ class InvalidQueryError(Exception): class OperationError(Exception): pass +class MultipleObjectsReturned(Exception): + pass + +class DoesNotExist(Exception): + pass class Q(object): @@ -290,6 +295,20 @@ class QuerySet(object): return mongo_query + def get(self): + """Retrieve the the matching object raising + 'MultipleObjectsReturned' or 'DoesNotExist' exceptions + if multiple or no results are found. + """ + count = self.count() + if count == 1: + return self[0] + elif count > 1: + raise MultipleObjectsReturned + else: + raise DoesNotExist + + def first(self): """Retrieve the first object matching the query. """ From 47e4dd40cd69f314f59703abb124f58268355f1f Mon Sep 17 00:00:00 2001 From: James Punteney Date: Sat, 16 Jan 2010 13:24:10 -0500 Subject: [PATCH 2/3] Making the query actually get called for get --- mongoengine/queryset.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mongoengine/queryset.py b/mongoengine/queryset.py index 7d89a447..92d20315 100644 --- a/mongoengine/queryset.py +++ b/mongoengine/queryset.py @@ -295,11 +295,12 @@ class QuerySet(object): return mongo_query - def get(self): + def get(self, *q_objs, **query): """Retrieve the the matching object raising 'MultipleObjectsReturned' or 'DoesNotExist' exceptions if multiple or no results are found. """ + self.__call__(*q_objs, **query) count = self.count() if count == 1: return self[0] From e0becc109d1f6a236e500e65b4f8ff30b34b9e6d Mon Sep 17 00:00:00 2001 From: James Punteney Date: Sat, 16 Jan 2010 14:51:13 -0500 Subject: [PATCH 3/3] Adding tests to test the get query --- mongoengine/queryset.py | 1 - tests/queryset.py | 23 ++++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/mongoengine/queryset.py b/mongoengine/queryset.py index 92d20315..4a563b53 100644 --- a/mongoengine/queryset.py +++ b/mongoengine/queryset.py @@ -14,7 +14,6 @@ REPR_OUTPUT_SIZE = 20 class InvalidQueryError(Exception): pass - class OperationError(Exception): pass diff --git a/tests/queryset.py b/tests/queryset.py index 93dc0747..bf8af758 100644 --- a/tests/queryset.py +++ b/tests/queryset.py @@ -2,7 +2,7 @@ import unittest import pymongo from datetime import datetime -from mongoengine.queryset import QuerySet +from mongoengine.queryset import QuerySet, MultipleObjectsReturned, DoesNotExist from mongoengine import * @@ -135,6 +135,27 @@ class QuerySetTest(unittest.TestCase): person = self.Person.objects.with_id(person1.id) self.assertEqual(person.name, "User A") + def test_find_only_one(self): + """Ensure that a query using find_one returns a valid 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_filter_chaining(self): """Ensure filters can be chained together. """