Fixed #19326 -- Added first() and last() methods to QuerySet

This commit is contained in:
Selwin Ong 2013-05-21 18:35:12 +03:00 committed by Anssi Kääriäinen
parent d595b61aca
commit ea9a0857d4
5 changed files with 92 additions and 0 deletions

View File

@ -186,6 +186,12 @@ class Manager(six.with_metaclass(RenameManagerMethods)):
def latest(self, *args, **kwargs): def latest(self, *args, **kwargs):
return self.get_queryset().latest(*args, **kwargs) return self.get_queryset().latest(*args, **kwargs)
def first(self):
return self.get_queryset().first()
def last(self):
return self.get_queryset().last()
def order_by(self, *args, **kwargs): def order_by(self, *args, **kwargs):
return self.get_queryset().order_by(*args, **kwargs) return self.get_queryset().order_by(*args, **kwargs)

View File

@ -498,6 +498,26 @@ class QuerySet(object):
def latest(self, field_name=None): def latest(self, field_name=None):
return self._earliest_or_latest(field_name=field_name, direction="-") return self._earliest_or_latest(field_name=field_name, direction="-")
def first(self):
"""
Returns the first object of a query, returns None if no match is found.
"""
qs = self if self.ordered else self.order_by('pk')
try:
return qs[0]
except IndexError:
return None
def last(self):
"""
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')
try:
return qs[0]
except IndexError:
return None
def in_bulk(self, id_list): def in_bulk(self, id_list):
""" """
Returns a dictionary mapping each of the given IDs to the object with Returns a dictionary mapping each of the given IDs to the object with

View File

@ -1585,6 +1585,36 @@ earliest
Works otherwise like :meth:`~django.db.models.query.QuerySet.latest` except Works otherwise like :meth:`~django.db.models.query.QuerySet.latest` except
the direction is changed. the direction is changed.
first
~~~~~
.. method:: first()
.. versionadded:: 1.6
Returns the first object matched by the queryset, or ``None`` if there
is no matching object. If the ``QuerySet`` has no ordering defined, then the
queryset is automatically ordered by the primary key.
Example::
p = Article.objects.order_by('title', 'pub_date').first()
Note that ``first()`` is a convenience method, the following code sample is
equivalent to the above example::
try:
p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
p = None
last
~~~~
.. method:: last()
.. versionadded:: 1.6
Works like :meth:`first()` except the ordering is reversed.
aggregate aggregate
~~~~~~~~~ ~~~~~~~~~

View File

@ -253,6 +253,11 @@ Minor features
allow users to specify the primary keys of objects they want to dump. allow users to specify the primary keys of objects they want to dump.
This option can only be used with one model. This option can only be used with one model.
* Added ``QuerySet`` methods :meth:`~django.db.models.query.QuerySet.first`
and :meth:`~django.db.models.query.QuerySet.last` which are convenience
methods returning the first or last object matching the filters. Returns
``None`` if there are no objects matching.
Backwards incompatible changes in 1.6 Backwards incompatible changes in 1.6
===================================== =====================================

View File

@ -121,3 +121,34 @@ class EarliestOrLatestTests(TestCase):
p2 = Person.objects.create(name="Stephanie", birthday=datetime(1960, 2, 3)) p2 = Person.objects.create(name="Stephanie", birthday=datetime(1960, 2, 3))
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)
def test_first(self):
p1 = Person.objects.create(name="Bob", birthday=datetime(1950, 1, 1))
p2 = Person.objects.create(name="Alice", birthday=datetime(1961, 2, 3))
self.assertEqual(
Person.objects.first(), p1)
self.assertEqual(
Person.objects.order_by('name').first(), p2)
self.assertEqual(
Person.objects.filter(birthday__lte=datetime(1955, 1, 1)).first(),
p1)
self.assertIs(
Person.objects.filter(birthday__lte=datetime(1940, 1, 1)).first(),
None)
def test_last(self):
p1 = Person.objects.create(
name="Alice", birthday=datetime(1950, 1, 1))
p2 = Person.objects.create(
name="Bob", birthday=datetime(1960, 2, 3))
# Note: by default PK ordering.
self.assertEqual(
Person.objects.last(), p2)
self.assertEqual(
Person.objects.order_by('-name').last(), p1)
self.assertEqual(
Person.objects.filter(birthday__lte=datetime(1955, 1, 1)).last(),
p1)
self.assertIs(
Person.objects.filter(birthday__lte=datetime(1940, 1, 1)).last(),
None)