Commit fe54377d authored by Nick Sandford's avatar Nick Sandford Committed by Anssi Kääriäinen
Browse files

Fixed #17813 -- Added a .earliest() method to QuerySet

Thanks a lot to everybody participating in developing this feature.
The patch was developed by multiple people, at least Trac aliases
tonnzor, jimmysong, Fandekasp and slurms.

Stylistic changes added by committer.
parent 37718eb5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -172,6 +172,9 @@ class Manager(object):
    def iterator(self, *args, **kwargs):
        return self.get_query_set().iterator(*args, **kwargs)

    def earliest(self, *args, **kwargs):
        return self.get_query_set().earliest(*args, **kwargs)

    def latest(self, *args, **kwargs):
        return self.get_query_set().latest(*args, **kwargs)

+15 −7
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ REPR_OUTPUT_SIZE = 20
# Pull into this namespace for backwards compatibility.
EmptyResultSet = sql.EmptyResultSet


class QuerySet(object):
    """
    Represents a lazy database lookup for a set of objects.
@@ -487,21 +488,28 @@ class QuerySet(object):
                    # Re-raise the IntegrityError with its original traceback.
                    six.reraise(*exc_info)

    def latest(self, field_name=None):
    def _earliest_or_latest(self, field_name=None, direction="-"):
        """
        Returns the latest object, according to the model's 'get_latest_by'
        option or optional given field_name.
        Returns the latest object, according to the model's
        'get_latest_by' option or optional given field_name.
        """
        latest_by = field_name or self.model._meta.get_latest_by
        assert bool(latest_by), "latest() requires either a field_name parameter or 'get_latest_by' in the model"
        order_by = field_name or getattr(self.model._meta, 'get_latest_by')
        assert bool(order_by), "earliest() and latest() require either a "\
            "field_name parameter or 'get_latest_by' in the model"
        assert self.query.can_filter(), \
            "Cannot change a query once a slice has been taken."
        obj = self._clone()
        obj.query.set_limits(high=1)
        obj.query.clear_ordering()
        obj.query.add_ordering('-%s' % latest_by)
        obj.query.add_ordering('%s%s' % (direction, order_by))
        return obj.get()

    def earliest(self, field_name=None):
        return self._earliest_or_latest(field_name=field_name, direction="")

    def latest(self, field_name=None):
        return self._earliest_or_latest(field_name=field_name, direction="-")

    def in_bulk(self, id_list):
        """
        Returns a dictionary mapping each of the given IDs to the object with
+2 −1
Original line number Diff line number Diff line
@@ -86,7 +86,8 @@ Django quotes column and table names behind the scenes.
    The name of an orderable field in the model, typically a :class:`DateField`,
    :class:`DateTimeField`, or :class:`IntegerField`. This specifies the default
    field to use in your model :class:`Manager`'s
    :meth:`~django.db.models.query.QuerySet.latest` method.
    :meth:`~django.db.models.query.QuerySet.latest` and
    :meth:`~django.db.models.query.QuerySet.earliest` methods.

    Example::

+15 −6
Original line number Diff line number Diff line
@@ -1477,14 +1477,23 @@ This example returns the latest ``Entry`` in the table, according to the

If your model's :ref:`Meta <meta-options>` specifies
:attr:`~django.db.models.Options.get_latest_by`, you can leave off the
``field_name`` argument to ``latest()``. Django will use the field specified
in :attr:`~django.db.models.Options.get_latest_by` by default.
``field_name`` argument to ``earliest()`` or ``latest()``. Django will use the
field specified in :attr:`~django.db.models.Options.get_latest_by` by default.

Like :meth:`get()`, ``latest()`` raises
:exc:`~django.core.exceptions.DoesNotExist` if there is no object with the given
parameters.
Like :meth:`get()`, ``earliest()`` and ``latest()`` raise
:exc:`~django.core.exceptions.DoesNotExist` if there is no object with the
given parameters.

Note that ``earliest()`` and ``latest()`` exist purely for convenience and
readability.

earliest
~~~~~~~~

.. method:: earliest(field_name=None)

Note ``latest()`` exists purely for convenience and readability.
Works otherwise like :meth:`~django.db.models.query.QuerySet.latest` except
the direction is changed.

aggregate
~~~~~~~~~
+3 −0
Original line number Diff line number Diff line
@@ -28,6 +28,9 @@ Minor features
  undefined if the given ``QuerySet`` isn't ordered and there are more than
  one ordered values to compare against.

* Added :meth:`~django.db.models.query.QuerySet.earliest` for symmetry with
  :meth:`~django.db.models.query.QuerySet.latest`.

Backwards incompatible changes in 1.6
=====================================

Loading