diff options
| -rw-r--r-- | django/db/models/expressions.py | 2 | ||||
| -rw-r--r-- | docs/releases/5.2.9.txt | 4 | ||||
| -rw-r--r-- | tests/aggregation/test_filter_argument.py | 11 | ||||
| -rw-r--r-- | tests/expressions/tests.py | 18 |
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 |
