From 57d58b4dc90397158ceedf2eaa221b857deaef99 Mon Sep 17 00:00:00 2001 From: "utkarsh.arya@zomato.com" Date: Sat, 15 Nov 2025 22:59:52 +0000 Subject: [PATCH] Fix GROUP BY to exclude constants in ExpressionWrapper Ensure ExpressionWrapper passes group by columns from its inner expression, preventing constant expressions from being incorrectly included in the GROUP BY clause. This addresses SQL errors on Postgres with aggregates (# issue). Add regression test to verify correct SQL generation and results. --- django/db/models/expressions.py | 3 +++ tests/expressions/tests.py | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index c1a76584f0..a8f8b427ca 100644 --- a/django/db/models/expressions.py +++ b/django/db/models/expressions.py @@ -866,6 +866,9 @@ class ExpressionWrapper(Expression): def as_sql(self, compiler, connection): return self.expression.as_sql(compiler, connection) + def get_group_by_cols(self, alias=None): + return self.expression.get_group_by_cols(alias) + def __repr__(self): return "{}({})".format(self.__class__.__name__, self.expression) diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py index 72bca4f205..bf40f7f541 100644 --- a/tests/expressions/tests.py +++ b/tests/expressions/tests.py @@ -781,6 +781,24 @@ class BasicExpressionsTests(TestCase): [self.example_inc.ceo, self.max], ) + def test_expressionwrapper_with_constant_values_aggregate(self): + # Constant expressions wrapped in ExpressionWrapper should not be + # included in the GROUP BY clause. + expr = ExpressionWrapper(Value(3), output_field=IntegerField()) + qs = Employee.objects.annotate( + expr_res=expr + ).values('expr_res', 'lastname').annotate(sum=Sum('salary')) + # This should work without raising an error about constants in GROUP BY + results = list(qs) + # Verify that the constant expression is in the SELECT but not in GROUP BY + sql = str(qs.query) + self.assertIn('3', sql) # Constant in SELECT + # Verify results are grouped by lastname only + self.assertEqual(len(results), 3) # Smith, Meyer, Mustermann + # All results should have expr_res=3 + for result in results: + self.assertEqual(result['expr_res'], 3) + class IterableLookupInnerExpressionsTests(TestCase): @classmethod