summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnssi Kääriäinen <anssi.kaariainen@thl.fi>2015-04-15 08:46:19 +0300
committerClaude Paroz <claude@2xlibre.net>2015-04-16 09:42:42 +0200
commit70ff455a35066a1b6e2db03f211f56c7b38285eb (patch)
tree3f8debc69b22f2db6f6a84109fd803a6d2661afe
parentc38d8f0f871e3117c1f8f32d87f3b135b7891412 (diff)
[1.8.x] Fixed #24615 -- ordering by expression not part of SELECT
Fixed queries where an expression was used in order_by() but the expression wasn't in the query's select clause (for example the expression could be masked by .values() call) Thanks to Trac alias MattBlack85 for the report. Backport of fb5c7748da from master.
-rw-r--r--django/contrib/gis/db/backends/base/adapter.py3
-rw-r--r--django/contrib/gis/db/backends/postgis/adapter.py3
-rw-r--r--django/db/models/sql/compiler.py7
-rw-r--r--docs/releases/1.8.1.txt4
-rw-r--r--tests/gis_tests/distapp/tests.py9
5 files changed, 25 insertions, 1 deletions
diff --git a/django/contrib/gis/db/backends/base/adapter.py b/django/contrib/gis/db/backends/base/adapter.py
index ca77124351..25f8846fa8 100644
--- a/django/contrib/gis/db/backends/base/adapter.py
+++ b/django/contrib/gis/db/backends/base/adapter.py
@@ -12,6 +12,9 @@ class WKTAdapter(object):
return False
return self.wkt == other.wkt and self.srid == other.srid
+ def __hash__(self):
+ return hash((self.wkt, self.srid))
+
def __str__(self):
return self.wkt
diff --git a/django/contrib/gis/db/backends/postgis/adapter.py b/django/contrib/gis/db/backends/postgis/adapter.py
index 172133693b..1fd0ee1cce 100644
--- a/django/contrib/gis/db/backends/postgis/adapter.py
+++ b/django/contrib/gis/db/backends/postgis/adapter.py
@@ -28,6 +28,9 @@ class PostGISAdapter(object):
return False
return (self.ewkb == other.ewkb) and (self.srid == other.srid)
+ def __hash__(self):
+ return hash((self.ewkb, self.srid))
+
def __str__(self):
return self.getquoted()
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index f1bb10e228..a695025167 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -253,10 +253,17 @@ class SQLCompiler(object):
descending = True if order == 'DESC' else False
if col in self.query.annotation_select:
+ # Reference to expression in SELECT clause
order_by.append((
OrderBy(Ref(col, self.query.annotation_select[col]), descending=descending),
True))
continue
+ if col in self.query.annotations:
+ # References to an expression which is masked out of the SELECT clause
+ order_by.append((
+ OrderBy(self.query.annotations[col], descending=descending),
+ False))
+ continue
if '.' in field:
# This came in through an extra(order_by=...) addition. Pass it
diff --git a/docs/releases/1.8.1.txt b/docs/releases/1.8.1.txt
index fd2140bbf0..976179c41e 100644
--- a/docs/releases/1.8.1.txt
+++ b/docs/releases/1.8.1.txt
@@ -49,3 +49,7 @@ Bugfixes
remove usage of referencing views by dotted path in
:func:`~django.conf.urls.url` which is deprecated in Django 1.8
(:ticket:`24635`).
+
+* Fixed queries where an expression was referenced in ``order_by()``, but wasn't
+ part of the select clause. An example query is
+ ``qs.annotate(foo=F('field')).values('pk').order_by('foo'))`` (:ticket:`24615`).
diff --git a/tests/gis_tests/distapp/tests.py b/tests/gis_tests/distapp/tests.py
index b9ba7e4df8..1889f2d9f9 100644
--- a/tests/gis_tests/distapp/tests.py
+++ b/tests/gis_tests/distapp/tests.py
@@ -1,6 +1,6 @@
from __future__ import unicode_literals
-from django.contrib.gis.geos import HAS_GEOS
+from django.contrib.gis.geos import HAS_GEOS, Point
from django.contrib.gis.measure import D # alias for Distance
from django.db import connection
from django.db.models import Q
@@ -383,3 +383,10 @@ class DistanceTest(TestCase):
z = SouthTexasZipcode.objects.distance(htown.point).area().get(name='78212')
self.assertIsNone(z.distance)
self.assertIsNone(z.area)
+
+ @skipUnlessDBFeature("has_distance_method")
+ def test_distance_order_by(self):
+ qs = SouthTexasCity.objects.distance(Point(3, 3)).order_by(
+ 'distance'
+ ).values_list('name', flat=True).filter(name__in=('San Antonio', 'Pearland'))
+ self.assertQuerysetEqual(qs, ['San Antonio', 'Pearland'], lambda x: x)