1
0
mirror of https://github.com/django/django.git synced 2025-03-12 10:22:37 +00:00

Fixed #36117 -- Raised ValueError when providing composite expressions to case / when.

Remove redundant Case and When.resolve_expression to delegate composite
expression support to BaseExpression.

Thanks Jacob Tyler Walls for the report and test.
This commit is contained in:
Simon Charette 2025-01-20 22:36:47 -05:00 committed by Sarah Boyce
parent a76035e925
commit 00c690efbc
2 changed files with 18 additions and 29 deletions

View File

@ -1577,20 +1577,6 @@ class When(Expression):
# We're only interested in the fields of the result expressions. # We're only interested in the fields of the result expressions.
return [self.result._output_field_or_none] return [self.result._output_field_or_none]
def resolve_expression(
self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False
):
c = self.copy()
c.is_summary = summarize
if hasattr(c.condition, "resolve_expression"):
c.condition = c.condition.resolve_expression(
query, allow_joins, reuse, summarize, False
)
c.result = c.result.resolve_expression(
query, allow_joins, reuse, summarize, for_save
)
return c
def as_sql(self, compiler, connection, template=None, **extra_context): def as_sql(self, compiler, connection, template=None, **extra_context):
connection.ops.check_expression_support(self) connection.ops.check_expression_support(self)
template_params = extra_context template_params = extra_context
@ -1658,20 +1644,6 @@ class Case(SQLiteNumericMixin, Expression):
def set_source_expressions(self, exprs): def set_source_expressions(self, exprs):
*self.cases, self.default = exprs *self.cases, self.default = exprs
def resolve_expression(
self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False
):
c = self.copy()
c.is_summary = summarize
for pos, case in enumerate(c.cases):
c.cases[pos] = case.resolve_expression(
query, allow_joins, reuse, summarize, for_save
)
c.default = c.default.resolve_expression(
query, allow_joins, reuse, summarize, for_save
)
return c
def copy(self): def copy(self):
c = super().copy() c = super().copy()
c.cases = c.cases[:] c.cases = c.cases[:]

View File

@ -1,4 +1,13 @@
from django.db.models import F, FilteredRelation, OuterRef, Q, Subquery, TextField from django.db.models import (
Case,
F,
FilteredRelation,
OuterRef,
Q,
Subquery,
TextField,
When,
)
from django.db.models.functions import Cast from django.db.models.functions import Cast
from django.db.models.lookups import Exact from django.db.models.lookups import Exact
from django.test import TestCase from django.test import TestCase
@ -409,6 +418,14 @@ class CompositePKFilterTests(TestCase):
with self.assertRaisesMessage(ValueError, msg): with self.assertRaisesMessage(ValueError, msg):
Comment.objects.filter(text__gt=Cast(F("pk"), TextField())).count() Comment.objects.filter(text__gt=Cast(F("pk"), TextField())).count()
def test_filter_case_when(self):
msg = "When expression does not support composite primary keys."
with self.assertRaisesMessage(ValueError, msg):
Comment.objects.filter(text=Case(When(text="", then="pk")))
msg = "Case expression does not support composite primary keys."
with self.assertRaisesMessage(ValueError, msg):
Comment.objects.filter(text=Case(When(text="", then="text"), default="pk"))
def test_outer_ref_pk(self): def test_outer_ref_pk(self):
subquery = Subquery(Comment.objects.filter(pk=OuterRef("pk")).values("id")) subquery = Subquery(Comment.objects.filter(pk=OuterRef("pk")).values("id"))
tests = [ tests = [