mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
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):
|
def reverse(self):
|
||||||
"""Reverse the ordering of the QuerySet."""
|
"""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 = self._clone()
|
||||||
clone.query.standard_ordering = not clone.query.standard_ordering
|
clone.query.standard_ordering = not clone.query.standard_ordering
|
||||||
return clone
|
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.unregister(User)
|
||||||
admin.site.register(User, MyUserAdmin)
|
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
|
Miscellaneous
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
@ -361,6 +361,9 @@ every *second* object of the first 10::
|
|||||||
|
|
||||||
>>> Entry.objects.all()[:10:2]
|
>>> 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
|
To retrieve a *single* object rather than a list
|
||||||
(e.g. ``SELECT foo FROM bar LIMIT 1``), use a simple index instead of a
|
(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
|
slice. For example, this returns the first ``Entry`` in the database, after
|
||||||
|
@ -203,6 +203,14 @@ class OrderingTests(TestCase):
|
|||||||
attrgetter("headline")
|
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):
|
def test_extra_ordering(self):
|
||||||
"""
|
"""
|
||||||
Ordering can be based on fields included from an 'extra' clause
|
Ordering can be based on fields included from an 'extra' clause
|
||||||
|
@ -731,10 +731,10 @@ class Queries1Tests(TestCase):
|
|||||||
q.extra(select={'foo': "1"}),
|
q.extra(select={'foo': "1"}),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
self.assertQuerysetEqual(q.reverse(), [])
|
||||||
q.query.low_mark = 1
|
q.query.low_mark = 1
|
||||||
with self.assertRaisesMessage(AssertionError, 'Cannot change a query once a slice has been taken'):
|
with self.assertRaisesMessage(AssertionError, 'Cannot change a query once a slice has been taken'):
|
||||||
q.extra(select={'foo': "1"})
|
q.extra(select={'foo': "1"})
|
||||||
self.assertQuerysetEqual(q.reverse(), [])
|
|
||||||
self.assertQuerysetEqual(q.defer('meal'), [])
|
self.assertQuerysetEqual(q.defer('meal'), [])
|
||||||
self.assertQuerysetEqual(q.only('meal'), [])
|
self.assertQuerysetEqual(q.only('meal'), [])
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user