mirror of https://github.com/django/django.git
Fixed #22550 -- Prohibited QuerySet.last()/reverse() after slicing.
This commit is contained in:
parent
84fb50df67
commit
eee34ef64c
|
@ -944,6 +944,8 @@ class QuerySet:
|
|||
|
||||
def reverse(self):
|
||||
"""Reverse the ordering of the QuerySet."""
|
||||
if not self.query.can_filter():
|
||||
raise TypeError('Cannot reverse a query once a slice has been taken.')
|
||||
clone = self._clone()
|
||||
clone.query.standard_ordering = not clone.query.standard_ordering
|
||||
return clone
|
||||
|
|
|
@ -314,6 +314,18 @@ If you wish to keep this restriction in the admin when editing users, set
|
|||
admin.site.unregister(User)
|
||||
admin.site.register(User, MyUserAdmin)
|
||||
|
||||
``QuerySet.reverse()`` and ``last()`` are prohibited after slicing
|
||||
------------------------------------------------------------------
|
||||
|
||||
Calling ``QuerySet.reverse()`` or ``last()`` on a sliced queryset leads to
|
||||
unexpected results due to the slice being applied after reordering. This is
|
||||
now prohibited, e.g.::
|
||||
|
||||
>>> Model.objects.all()[:2].reverse()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: Cannot reverse a query once a slice has been taken.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
|
|
|
@ -361,6 +361,9 @@ every *second* object of the first 10::
|
|||
|
||||
>>> Entry.objects.all()[:10:2]
|
||||
|
||||
Further filtering or ordering of a sliced queryset is prohibited due to the
|
||||
ambiguous nature of how that might work.
|
||||
|
||||
To retrieve a *single* object rather than a list
|
||||
(e.g. ``SELECT foo FROM bar LIMIT 1``), use a simple index instead of a
|
||||
slice. For example, this returns the first ``Entry`` in the database, after
|
||||
|
|
|
@ -203,6 +203,14 @@ class OrderingTests(TestCase):
|
|||
attrgetter("headline")
|
||||
)
|
||||
|
||||
def test_no_reordering_after_slicing(self):
|
||||
msg = 'Cannot reverse a query once a slice has been taken.'
|
||||
qs = Article.objects.all()[0:2]
|
||||
with self.assertRaisesMessage(TypeError, msg):
|
||||
qs.reverse()
|
||||
with self.assertRaisesMessage(TypeError, msg):
|
||||
qs.last()
|
||||
|
||||
def test_extra_ordering(self):
|
||||
"""
|
||||
Ordering can be based on fields included from an 'extra' clause
|
||||
|
|
|
@ -731,10 +731,10 @@ class Queries1Tests(TestCase):
|
|||
q.extra(select={'foo': "1"}),
|
||||
[]
|
||||
)
|
||||
self.assertQuerysetEqual(q.reverse(), [])
|
||||
q.query.low_mark = 1
|
||||
with self.assertRaisesMessage(AssertionError, 'Cannot change a query once a slice has been taken'):
|
||||
q.extra(select={'foo': "1"})
|
||||
self.assertQuerysetEqual(q.reverse(), [])
|
||||
self.assertQuerysetEqual(q.defer('meal'), [])
|
||||
self.assertQuerysetEqual(q.only('meal'), [])
|
||||
|
||||
|
|
Loading…
Reference in New Issue