summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/db/models/expressions.py2
-rw-r--r--docs/releases/5.2.9.txt4
-rw-r--r--tests/aggregation/test_filter_argument.py11
-rw-r--r--tests/expressions/tests.py18
4 files changed, 34 insertions, 1 deletions
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 3e1bcdbd2b..4284c84375 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -425,7 +425,7 @@ class BaseExpression:
clone = self.copy()
clone.set_source_expressions(
[
- expr.replace_expressions(replacements) if expr else None
+ None if expr is None else expr.replace_expressions(replacements)
for expr in source_expressions
]
)
diff --git a/docs/releases/5.2.9.txt b/docs/releases/5.2.9.txt
index 588c278be5..515b233b8a 100644
--- a/docs/releases/5.2.9.txt
+++ b/docs/releases/5.2.9.txt
@@ -16,3 +16,7 @@ Bugfixes
* Fixed a bug in Django 5.2 on PostgreSQL where ``bulk_create()`` did not apply
a field's custom query placeholders (:ticket:`36748`).
+
+* Fixed a regression in Django 5.2.2 that caused a crash when using aggregate
+ functions with an empty ``Q`` filter over a queryset with annotations
+ (:ticket:`36751`).
diff --git a/tests/aggregation/test_filter_argument.py b/tests/aggregation/test_filter_argument.py
index 1a17703a86..59588d30d0 100644
--- a/tests/aggregation/test_filter_argument.py
+++ b/tests/aggregation/test_filter_argument.py
@@ -88,6 +88,17 @@ class FilteredAggregateTests(TestCase):
agg = Count("pk", filter=Q())
self.assertEqual(Author.objects.aggregate(count=agg)["count"], 3)
+ def test_empty_filtered_aggregates_with_annotation(self):
+ agg = Count("pk", filter=Q())
+ self.assertEqual(
+ Author.objects.annotate(
+ age_annotation=F("age"),
+ ).aggregate(
+ count=agg
+ )["count"],
+ 3,
+ )
+
def test_double_filtered_aggregates(self):
agg = Sum("age", filter=Q(Q(name="test2") & ~Q(name="test")))
self.assertEqual(Author.objects.aggregate(age=agg)["age"], 60)
diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py
index 5f61f65ac0..9212b677a2 100644
--- a/tests/expressions/tests.py
+++ b/tests/expressions/tests.py
@@ -1537,6 +1537,24 @@ class SimpleExpressionTests(SimpleTestCase):
with self.assertRaisesMessage(ValueError, msg):
expression.get_expression_for_validation()
+ def test_replace_expressions_falsey(self):
+ class AssignableExpression(Expression):
+ def __init__(self, *source_expressions):
+ super().__init__()
+ self.set_source_expressions(list(source_expressions))
+
+ def get_source_expressions(self):
+ return self.source_expressions
+
+ def set_source_expressions(self, exprs):
+ self.source_expressions = exprs
+
+ expression = AssignableExpression()
+ falsey = Q()
+ expression.set_source_expressions([falsey])
+ replaced = expression.replace_expressions({"replacement": Expression()})
+ self.assertEqual(replaced.get_source_expressions(), [falsey])
+
class ExpressionsNumericTests(TestCase):
@classmethod