diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 3360f9c806..850734709d 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -322,10 +322,15 @@ class SQLCompiler: if col in self.query.annotations: # References to an expression which is masked out of the SELECT # clause. - expr = self.query.annotations[col] - if isinstance(expr, Value): - # output_field must be resolved for constants. - expr = Cast(expr, expr.output_field) + if self.query.combinator and self.select: + # Don't use the resolved annotation because other + # combinated queries might define it differently. + expr = F(col) + else: + expr = self.query.annotations[col] + if isinstance(expr, Value): + # output_field must be resolved for constants. + expr = Cast(expr, expr.output_field) order_by.append((OrderBy(expr, descending=descending), False)) continue @@ -378,10 +383,14 @@ class SQLCompiler: else: if col_alias: raise DatabaseError('ORDER BY term does not match any column in the result set.') - # Add column used in ORDER BY clause without an alias to - # the selected columns. - self.query.add_select_col(src) - resolved.set_source_expressions([RawSQL('%d' % len(self.query.select), ())]) + # Add column used in ORDER BY clause to the selected + # columns and to each combined query. + order_by_idx = len(self.query.select) + 1 + col_name = f'__orderbycol{order_by_idx}' + for q in self.query.combined_queries: + q.add_annotation(expr_src, col_name) + self.query.add_select_col(resolved, col_name) + resolved.set_source_expressions([RawSQL(f'{order_by_idx}', ())]) sql, params = self.compile(resolved) # Don't add the same column twice, but the order direction is # not taken into account so we strip it. When this entire method diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index a7dadf5a40..5a7dc25fd9 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -1881,9 +1881,9 @@ class Query(BaseExpression): self.select = () self.values_select = () - def add_select_col(self, col): + def add_select_col(self, col, name): self.select += col, - self.values_select += col.output_field.name, + self.values_select += name, def set_select(self, cols): self.default_cols = False diff --git a/tests/queries/test_qs_combinators.py b/tests/queries/test_qs_combinators.py index 073f104a22..58c03f09fe 100644 --- a/tests/queries/test_qs_combinators.py +++ b/tests/queries/test_qs_combinators.py @@ -211,6 +211,28 @@ class QuerySetSetOperationTests(TestCase): with self.subTest(qs=qs): self.assertEqual(list(qs), expected_result) + def test_union_with_values_list_and_order_on_annotation(self): + qs1 = Number.objects.annotate( + annotation=Value(-1), + multiplier=F('annotation'), + ).filter(num__gte=6) + qs2 = Number.objects.annotate( + annotation=Value(2), + multiplier=F('annotation'), + ).filter(num__lte=5) + self.assertSequenceEqual( + qs1.union(qs2).order_by('annotation', 'num').values_list('num', flat=True), + [6, 7, 8, 9, 0, 1, 2, 3, 4, 5], + ) + self.assertQuerysetEqual( + qs1.union(qs2).order_by( + F('annotation') * F('multiplier'), + 'num', + ).values('num'), + [6, 7, 8, 9, 0, 1, 2, 3, 4, 5], + operator.itemgetter('num'), + ) + def test_count_union(self): qs1 = Number.objects.filter(num__lte=1).values('num') qs2 = Number.objects.filter(num__gte=2, num__lte=3).values('num')