Fixed #23555 -- Avoided suppressing IndexError in QuerySet.first() and .last()
This commit is contained in:
parent
9e2e4cb6dd
commit
ca61195827
|
@ -516,21 +516,19 @@ class QuerySet(object):
|
||||||
"""
|
"""
|
||||||
Returns the first object of a query, returns None if no match is found.
|
Returns the first object of a query, returns None if no match is found.
|
||||||
"""
|
"""
|
||||||
qs = self if self.ordered else self.order_by('pk')
|
objects = list((self if self.ordered else self.order_by('pk'))[:1])
|
||||||
try:
|
if objects:
|
||||||
return qs[0]
|
return objects[0]
|
||||||
except IndexError:
|
return None
|
||||||
return None
|
|
||||||
|
|
||||||
def last(self):
|
def last(self):
|
||||||
"""
|
"""
|
||||||
Returns the last object of a query, returns None if no match is found.
|
Returns the last object of a query, returns None if no match is found.
|
||||||
"""
|
"""
|
||||||
qs = self.reverse() if self.ordered else self.order_by('-pk')
|
objects = list((self.reverse() if self.ordered else self.order_by('-pk'))[:1])
|
||||||
try:
|
if objects:
|
||||||
return qs[0]
|
return objects[0]
|
||||||
except IndexError:
|
return None
|
||||||
return None
|
|
||||||
|
|
||||||
def in_bulk(self, id_list):
|
def in_bulk(self, id_list):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -14,3 +14,18 @@ class Person(models.Model):
|
||||||
name = models.CharField(max_length=30)
|
name = models.CharField(max_length=30)
|
||||||
birthday = models.DateField()
|
birthday = models.DateField()
|
||||||
# Note that this model doesn't have "get_latest_by" set.
|
# Note that this model doesn't have "get_latest_by" set.
|
||||||
|
|
||||||
|
|
||||||
|
# Ticket #23555 - model with an intentionally broken QuerySet.__iter__ method.
|
||||||
|
|
||||||
|
class IndexErrorQuerySet(models.QuerySet):
|
||||||
|
"""
|
||||||
|
Emulates the case when some internal code raises an unexpected
|
||||||
|
IndexError.
|
||||||
|
"""
|
||||||
|
def __iter__(self):
|
||||||
|
raise IndexError
|
||||||
|
|
||||||
|
|
||||||
|
class IndexErrorArticle(Article):
|
||||||
|
objects = IndexErrorQuerySet.as_manager()
|
||||||
|
|
|
@ -4,7 +4,7 @@ from datetime import datetime
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from .models import Article, Person
|
from .models import Article, Person, IndexErrorArticle
|
||||||
|
|
||||||
|
|
||||||
class EarliestOrLatestTests(TestCase):
|
class EarliestOrLatestTests(TestCase):
|
||||||
|
@ -122,6 +122,9 @@ class EarliestOrLatestTests(TestCase):
|
||||||
self.assertRaises(AssertionError, Person.objects.latest)
|
self.assertRaises(AssertionError, Person.objects.latest)
|
||||||
self.assertEqual(Person.objects.latest("birthday"), p2)
|
self.assertEqual(Person.objects.latest("birthday"), p2)
|
||||||
|
|
||||||
|
|
||||||
|
class TestFirstLast(TestCase):
|
||||||
|
|
||||||
def test_first(self):
|
def test_first(self):
|
||||||
p1 = Person.objects.create(name="Bob", birthday=datetime(1950, 1, 1))
|
p1 = Person.objects.create(name="Bob", birthday=datetime(1950, 1, 1))
|
||||||
p2 = Person.objects.create(name="Alice", birthday=datetime(1961, 2, 3))
|
p2 = Person.objects.create(name="Alice", birthday=datetime(1961, 2, 3))
|
||||||
|
@ -152,3 +155,24 @@ class EarliestOrLatestTests(TestCase):
|
||||||
self.assertIs(
|
self.assertIs(
|
||||||
Person.objects.filter(birthday__lte=datetime(1940, 1, 1)).last(),
|
Person.objects.filter(birthday__lte=datetime(1940, 1, 1)).last(),
|
||||||
None)
|
None)
|
||||||
|
|
||||||
|
def test_index_error_not_suppressed(self):
|
||||||
|
"""
|
||||||
|
#23555 -- Unexpected IndexError exceptions in QuerySet iteration
|
||||||
|
shouldn't be suppressed.
|
||||||
|
"""
|
||||||
|
def check():
|
||||||
|
# We know that we've broken the __iter__ method, so the queryset
|
||||||
|
# should always raise an exception.
|
||||||
|
self.assertRaises(IndexError, lambda: IndexErrorArticle.objects.all()[0])
|
||||||
|
self.assertRaises(IndexError, IndexErrorArticle.objects.all().first)
|
||||||
|
self.assertRaises(IndexError, IndexErrorArticle.objects.all().last)
|
||||||
|
|
||||||
|
check()
|
||||||
|
|
||||||
|
# And it does not matter if there are any records in the DB.
|
||||||
|
IndexErrorArticle.objects.create(
|
||||||
|
headline="Article 1", pub_date=datetime(2005, 7, 26),
|
||||||
|
expire_date=datetime(2005, 9, 1)
|
||||||
|
)
|
||||||
|
check()
|
||||||
|
|
Loading…
Reference in New Issue