[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.
This commit is contained in:
Anssi Kääriäinen 2015-04-15 08:46:19 +03:00 committed by Claude Paroz
parent c38d8f0f87
commit 70ff455a35
5 changed files with 25 additions and 1 deletions

View File

@ -12,6 +12,9 @@ class WKTAdapter(object):
return False return False
return self.wkt == other.wkt and self.srid == other.srid return self.wkt == other.wkt and self.srid == other.srid
def __hash__(self):
return hash((self.wkt, self.srid))
def __str__(self): def __str__(self):
return self.wkt return self.wkt

View File

@ -28,6 +28,9 @@ class PostGISAdapter(object):
return False return False
return (self.ewkb == other.ewkb) and (self.srid == other.srid) return (self.ewkb == other.ewkb) and (self.srid == other.srid)
def __hash__(self):
return hash((self.ewkb, self.srid))
def __str__(self): def __str__(self):
return self.getquoted() return self.getquoted()

View File

@ -253,10 +253,17 @@ class SQLCompiler(object):
descending = True if order == 'DESC' else False descending = True if order == 'DESC' else False
if col in self.query.annotation_select: if col in self.query.annotation_select:
# Reference to expression in SELECT clause
order_by.append(( order_by.append((
OrderBy(Ref(col, self.query.annotation_select[col]), descending=descending), OrderBy(Ref(col, self.query.annotation_select[col]), descending=descending),
True)) True))
continue 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: if '.' in field:
# This came in through an extra(order_by=...) addition. Pass it # This came in through an extra(order_by=...) addition. Pass it

View File

@ -49,3 +49,7 @@ Bugfixes
remove usage of referencing views by dotted path in remove usage of referencing views by dotted path in
:func:`~django.conf.urls.url` which is deprecated in Django 1.8 :func:`~django.conf.urls.url` which is deprecated in Django 1.8
(:ticket:`24635`). (: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`).

View File

@ -1,6 +1,6 @@
from __future__ import unicode_literals 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.contrib.gis.measure import D # alias for Distance
from django.db import connection from django.db import connection
from django.db.models import Q from django.db.models import Q
@ -383,3 +383,10 @@ class DistanceTest(TestCase):
z = SouthTexasZipcode.objects.distance(htown.point).area().get(name='78212') z = SouthTexasZipcode.objects.distance(htown.point).area().get(name='78212')
self.assertIsNone(z.distance) self.assertIsNone(z.distance)
self.assertIsNone(z.area) 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)