Fixed #6785 -- Made QuerySet.get() fetch a limited number of rows.

Thanks Patryk Zawadzki.
This commit is contained in:
Tim Graham 2013-07-02 11:25:01 -04:00
parent 181f63c22d
commit da79ccca1d
2 changed files with 33 additions and 3 deletions

View File

@ -19,6 +19,10 @@ from django.utils.functional import partition
from django.utils import six from django.utils import six
from django.utils import timezone from django.utils import timezone
# The maximum number (one less than the max to be precise) of results to fetch
# in a get() query
MAX_GET_RESULTS = 20
# 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
@ -297,6 +301,7 @@ class QuerySet(object):
clone = self.filter(*args, **kwargs) clone = self.filter(*args, **kwargs)
if self.query.can_filter(): if self.query.can_filter():
clone = clone.order_by() clone = clone.order_by()
clone = clone[:MAX_GET_RESULTS + 1]
num = len(clone) num = len(clone)
if num == 1: if num == 1:
return clone._result_cache[0] return clone._result_cache[0]
@ -305,8 +310,11 @@ class QuerySet(object):
"%s matching query does not exist." % "%s matching query does not exist." %
self.model._meta.object_name) self.model._meta.object_name)
raise self.model.MultipleObjectsReturned( raise self.model.MultipleObjectsReturned(
"get() returned more than one %s -- it returned %s!" % "get() returned more than one %s -- it returned %s!" % (
(self.model._meta.object_name, num)) self.model._meta.object_name,
num if num <= MAX_GET_RESULTS else 'more than %s' % MAX_GET_RESULTS
)
)
def create(self, **kwargs): def create(self, **kwargs):
""" """

View File

@ -6,7 +6,7 @@ import threading
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.db import connections, DEFAULT_DB_ALIAS from django.db import connections, DEFAULT_DB_ALIAS
from django.db.models.fields import Field, FieldDoesNotExist from django.db.models.fields import Field, FieldDoesNotExist
from django.db.models.query import QuerySet, EmptyQuerySet, ValuesListQuerySet from django.db.models.query import QuerySet, EmptyQuerySet, ValuesListQuerySet, MAX_GET_RESULTS
from django.test import TestCase, TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature from django.test import TestCase, TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature
from django.utils import six from django.utils import six
from django.utils.translation import ugettext_lazy from django.utils.translation import ugettext_lazy
@ -155,6 +155,28 @@ class ModelTest(TestCase):
pub_date__month=7, pub_date__month=7,
) )
def test_multiple_objects_max_num_fetched(self):
"""
#6785 - get() should fetch a limited number of results.
"""
Article.objects.bulk_create(
Article(headline='Area %s' % i, pub_date=datetime(2005, 7, 28))
for i in range(MAX_GET_RESULTS)
)
six.assertRaisesRegex(self,
MultipleObjectsReturned,
"get\(\) returned more than one Article -- it returned %d!" % MAX_GET_RESULTS,
Article.objects.get,
headline__startswith='Area',
)
Article.objects.create(headline='Area %s' % MAX_GET_RESULTS, pub_date=datetime(2005, 7, 28))
six.assertRaisesRegex(self,
MultipleObjectsReturned,
"get\(\) returned more than one Article -- it returned more than %d!" % MAX_GET_RESULTS,
Article.objects.get,
headline__startswith='Area',
)
def test_object_creation(self): def test_object_creation(self):
# Create an Article. # Create an Article.
a = Article( a = Article(