Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

queryset-refactor: Implemented the reverse() method on querysets.

Refs #5012.


git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7148 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 6ad9c684aa23c62710047f94b8febc681cc30282 1 parent 7355fa6
@malcolmt malcolmt authored
View
3  django/db/models/manager.py
@@ -104,6 +104,9 @@ def values(self, *args, **kwargs):
def update(self, *args, **kwargs):
return self.get_query_set().update(*args, **kwargs)
+ def reverse(self, *args, **kwargs):
+ return self.get_query_set().reverse(*args, **kwargs)
+
def _insert(self, *args, **kwargs):
return self.get_query_set()._insert(*args, **kwargs)
View
8 django/db/models/query.py
@@ -409,6 +409,14 @@ def extra(self, select=None, where=None, params=None, tables=None,
clone.query.extra_order_by = order_by
return clone
+ def reverse(self):
+ """
+ Reverses the ordering of the queryset.
+ """
+ clone = self._clone()
+ clone.query.standard_ordering = not clone.query.standard_ordering
+ return clone
+
###################
# PRIVATE METHODS #
###################
View
16 django/db/models/sql/query.py
@@ -92,6 +92,7 @@ def __init__(self, model, connection, where=WhereNode):
self.quote_cache = {}
self.default_cols = True
self.default_ordering = True
+ self.standard_ordering = True
# SQL-related attributes
self.select = []
@@ -160,6 +161,7 @@ def clone(self, klass=None, **kwargs):
obj.quote_cache = {}
obj.default_cols = self.default_cols
obj.default_ordering = self.default_ordering
+ obj.standard_ordering = self.standard_ordering
obj.select = self.select[:]
obj.tables = self.tables[:]
obj.where = copy.deepcopy(self.where)
@@ -487,23 +489,27 @@ def get_ordering(self):
distinct = self.distinct
select_aliases = self._select_aliases
result = []
+ if self.standard_ordering:
+ asc, desc = ORDER_DIR['ASC']
+ else:
+ asc, desc = ORDER_DIR['DESC']
for field in ordering:
if field == '?':
result.append(self.connection.ops.random_function_sql())
continue
if isinstance(field, int):
if field < 0:
- order = 'DESC'
+ order = desc
field = -field
else:
- order = 'ASC'
+ order = asc
result.append('%s %s' % (field, order))
continue
if '.' in field:
# This came in through an extra(ordering=...) addition. Pass it
# on verbatim, after mapping the table name to an alias, if
# necessary.
- col, order = get_order_dir(field)
+ col, order = get_order_dir(field, asc)
table, col = col.split('.', 1)
elt = '%s.%s' % (qn(self.table_alias(table)[0]), col)
if not distinct or elt in select_aliases:
@@ -512,12 +518,12 @@ def get_ordering(self):
# 'col' is of the form 'field' or 'field1__field2' or
# '-field1__field2__field', etc.
for table, col, order in self.find_ordering_name(field,
- self.model._meta):
+ self.model._meta, default_order=asc):
elt = '%s.%s' % (qn(table), qn(col))
if not distinct or elt in select_aliases:
result.append('%s %s' % (elt, order))
else:
- col, order = get_order_dir(field)
+ col, order = get_order_dir(field, asc)
elt = qn(col)
if not distinct or elt in select_aliases:
result.append('%s %s' % (elt, order))
View
20 docs/db-api.txt
@@ -554,6 +554,26 @@ There's no way to specify whether ordering should be case sensitive. With
respect to case-sensitivity, Django will order results however your database
backend normally orders them.
+``reverse()``
+~~~~~~~~~~~~~
+
+**New in Django development version**
+
+If you want to reverse the order in which a queryset's elements are returned,
+you can use the ``reverse()`` method. Calling ``reverse()`` a second time
+restores the ordering back to the normal direction.
+
+To retrieve the ''last'' five items in a queryset, you could do this::
+
+ my_queryset.reverse()[:5]
+
+Note that this is not quite the same as slicing from the end of a sequence in
+Python. The above example will return the last item first, then the
+penultimate item and so on. If we had a Python sequence and looked at
+``seq[:-5]``, we would see the fifth-last item first. Django doesn't support
+that mode of access (slicing from the end), since it is not possible to do it
+efficiently in SQL.
+
``distinct()``
~~~~~~~~~~~~~~
View
18 tests/modeltests/ordering/models.py
@@ -48,6 +48,13 @@ def __unicode__(self):
>>> Article.objects.order_by('pub_date', '-headline')
[<Article: Article 1>, <Article: Article 3>, <Article: Article 2>, <Article: Article 4>]
+# Only the last order_by has any effect (since they each override any previous
+# ordering).
+>>> Article.objects.order_by('id')
+[<Article: Article 1>, <Article: Article 2>, <Article: Article 3>, <Article: Article 4>]
+>>> Article.objects.order_by('id').order_by('-headline')
+[<Article: Article 4>, <Article: Article 3>, <Article: Article 2>, <Article: Article 1>]
+
# Use the 'stop' part of slicing notation to limit the results.
>>> Article.objects.order_by('headline')[:2]
[<Article: Article 1>, <Article: Article 2>]
@@ -65,10 +72,9 @@ def __unicode__(self):
>>> Article.objects.order_by('?')
[...]
-# order_by() overrides any previous ordering, so only the last one has any
-# effect.
->>> Article.objects.order_by('id')
-[<Article: Article 1>, <Article: Article 2>, <Article: Article 3>, <Article: Article 4>]
->>> Article.objects.order_by('id').order_by('-headline')
-[<Article: Article 4>, <Article: Article 3>, <Article: Article 2>, <Article: Article 1>]
+# Ordering can be reversed using the reverse() method on a queryset. This
+# allows you to extract things like "the last two items" (reverse and then
+# take the first two).
+>>> Article.objects.all().reverse()[:2]
+[<Article: Article 1>, <Article: Article 3>]
"""}
View
2  tests/regressiontests/queries/models.py
@@ -317,6 +317,8 @@ class Meta:
[<Item: four>]
>>> Item.objects.exclude(tags__name='t4').order_by('name').distinct()
[<Item: one>, <Item: three>, <Item: two>]
+>>> Item.objects.exclude(tags__name='t4').order_by('name').distinct().reverse()
+[<Item: two>, <Item: three>, <Item: one>]
>>> Author.objects.exclude(item__name='one').distinct().order_by('name')
[<Author: a2>, <Author: a3>, <Author: a4>]
Please sign in to comment.
Something went wrong with that request. Please try again.