mirror of
https://github.com/django/django.git
synced 2025-09-25 03:32:37 +00:00
Fixed #11557 -- Added support for a list of fields in Meta.get_latest_by and QuerySet.earliest()/latest().
This commit is contained in:
parent
093fd479d6
commit
ad4a8acdb5
7 changed files with 137 additions and 32 deletions
|
@ -25,6 +25,7 @@ from django.db.models.functions import Trunc
|
|||
from django.db.models.query_utils import InvalidQuery, Q
|
||||
from django.db.models.sql.constants import CURSOR, GET_ITERATOR_CHUNK_SIZE
|
||||
from django.utils import timezone
|
||||
from django.utils.deprecation import RemovedInDjango30Warning
|
||||
from django.utils.functional import cached_property, partition
|
||||
from django.utils.version import get_version
|
||||
|
||||
|
@ -525,27 +526,47 @@ class QuerySet:
|
|||
))
|
||||
return lookup, params
|
||||
|
||||
def _earliest_or_latest(self, field_name=None, direction="-"):
|
||||
def _earliest_or_latest(self, *fields, field_name=None):
|
||||
"""
|
||||
Return the latest object, according to the model's
|
||||
'get_latest_by' option or optional given field_name.
|
||||
"""
|
||||
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"
|
||||
if fields and field_name is not None:
|
||||
raise ValueError('Cannot use both positional arguments and the field_name keyword argument.')
|
||||
|
||||
order_by = None
|
||||
if field_name is not None:
|
||||
warnings.warn(
|
||||
'The field_name keyword argument to earliest() and latest() '
|
||||
'is deprecated in favor of passing positional arguments.',
|
||||
RemovedInDjango30Warning,
|
||||
)
|
||||
order_by = (field_name,)
|
||||
elif fields:
|
||||
order_by = fields
|
||||
else:
|
||||
order_by = getattr(self.model._meta, 'get_latest_by')
|
||||
if order_by and not isinstance(order_by, (tuple, list)):
|
||||
order_by = (order_by,)
|
||||
if order_by is None:
|
||||
raise ValueError(
|
||||
"earliest() and latest() require either fields as positional "
|
||||
"arguments or 'get_latest_by' in the model's Meta."
|
||||
)
|
||||
|
||||
assert self.query.can_filter(), \
|
||||
"Cannot change a query once a slice has been taken."
|
||||
obj = self._chain()
|
||||
obj.query.set_limits(high=1)
|
||||
obj.query.clear_ordering(force_empty=True)
|
||||
obj.query.add_ordering('%s%s' % (direction, order_by))
|
||||
obj.query.add_ordering(*order_by)
|
||||
return obj.get()
|
||||
|
||||
def earliest(self, field_name=None):
|
||||
return self._earliest_or_latest(field_name=field_name, direction="")
|
||||
def earliest(self, *fields, field_name=None):
|
||||
return self._earliest_or_latest(*fields, field_name=field_name)
|
||||
|
||||
def latest(self, field_name=None):
|
||||
return self._earliest_or_latest(field_name=field_name, direction="-")
|
||||
def latest(self, *fields, field_name=None):
|
||||
return self.reverse()._earliest_or_latest(*fields, field_name=field_name)
|
||||
|
||||
def first(self):
|
||||
"""Return the first object of a query or None if no match is found."""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue