summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Tramoy <laurenttramoy@gmail.com>2020-05-26 09:11:11 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-05-26 23:35:34 +0200
commitdf88f24b1f5805fc388a2184e56b964746608bf4 (patch)
tree09aec0a5b8fd76ba9f1a17db7987d17577874da4
parent114da2d0455594bae0bbda8f2b1d46c5ec854956 (diff)
[3.1.x] Fixed #31614 -- Fixed aliases ordering by OrderBy() expressions of combined queryset.
Backport of 2aac176e86204785f0f2ec4838049d8fed70870e from master
-rw-r--r--django/db/models/sql/compiler.py7
-rw-r--r--tests/queries/test_qs_combinators.py17
2 files changed, 22 insertions, 2 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 2c51561ae8..e6e840d8ea 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -6,7 +6,7 @@ from itertools import chain
from django.core.exceptions import EmptyResultSet, FieldError
from django.db import DatabaseError, NotSupportedError
from django.db.models.constants import LOOKUP_SEP
-from django.db.models.expressions import OrderBy, Random, RawSQL, Ref, Value
+from django.db.models.expressions import F, OrderBy, Random, RawSQL, Ref, Value
from django.db.models.functions import Cast
from django.db.models.query_utils import Q, select_related_descend
from django.db.models.sql.constants import (
@@ -361,13 +361,16 @@ class SQLCompiler:
resolved = expr.resolve_expression(self.query, allow_joins=True, reuse=None)
if self.query.combinator:
src = resolved.get_source_expressions()[0]
+ expr_src = expr.get_source_expressions()[0]
# Relabel order by columns to raw numbers if this is a combined
# query; necessary since the columns can't be referenced by the
# fully qualified name and the simple column names may collide.
for idx, (sel_expr, _, col_alias) in enumerate(self.select):
if is_ref and col_alias == src.refs:
src = src.source
- elif col_alias:
+ elif col_alias and not (
+ isinstance(expr_src, F) and col_alias == expr_src.name
+ ):
continue
if src == sel_expr:
resolved.set_source_expressions([RawSQL('%d' % (idx + 1), ())])
diff --git a/tests/queries/test_qs_combinators.py b/tests/queries/test_qs_combinators.py
index 1d159e1fed..bd8b0c309f 100644
--- a/tests/queries/test_qs_combinators.py
+++ b/tests/queries/test_qs_combinators.py
@@ -1,3 +1,5 @@
+import operator
+
from django.db import DatabaseError, NotSupportedError, connection
from django.db.models import Exists, F, IntegerField, OuterRef, Value
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
@@ -115,6 +117,21 @@ class QuerySetSetOperationTests(TestCase):
qs2 = Number.objects.filter(num__gte=2, num__lte=3)
self.assertNumbersEqual(qs1.union(qs2).order_by(F('num').desc()), [3, 2, 1, 0])
+ def test_ordering_by_f_expression_and_alias(self):
+ qs1 = Number.objects.filter(num__lte=1).values(alias=F('other_num'))
+ qs2 = Number.objects.filter(num__gte=2, num__lte=3).values(alias=F('other_num'))
+ self.assertQuerysetEqual(
+ qs1.union(qs2).order_by(F('alias').desc()),
+ [10, 9, 8, 7],
+ operator.itemgetter('alias'),
+ )
+ Number.objects.create(num=-1)
+ self.assertQuerysetEqual(
+ qs1.union(qs2).order_by(F('alias').desc(nulls_last=True)),
+ [10, 9, 8, 7, None],
+ operator.itemgetter('alias'),
+ )
+
def test_union_with_values(self):
ReservedName.objects.create(name='a', order=2)
qs1 = ReservedName.objects.all()