[1.8.x] Fixed #24924 -- Join promotion for multiple Case expressions
Backport of 541f4ea546
from master
This commit is contained in:
parent
469f1e362b
commit
0cfb7ed5c5
|
@ -87,10 +87,8 @@ class Q(tree.Node):
|
|||
def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
|
||||
# We must promote any new joins to left outer joins so that when Q is
|
||||
# used as an expression, rows aren't filtered due to joins.
|
||||
joins_before = query.tables[:]
|
||||
clause, joins = query._add_q(self, reuse, allow_joins=allow_joins, split_subq=False)
|
||||
joins_to_promote = [j for j in joins if j not in joins_before]
|
||||
query.promote_joins(joins_to_promote)
|
||||
query.promote_joins(joins)
|
||||
return clause
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -53,3 +53,7 @@ Bugfixes
|
|||
|
||||
* Fixed queryset annotations when using ``Case`` expressions with ``exclude()``
|
||||
(:ticket:`24833`).
|
||||
|
||||
* Corrected join promotion for multiple ``Case`` expressions. Annotating a
|
||||
query with multiple ``Case`` expressions could unexpectedly filter out
|
||||
results (:ticket:`24924`).
|
||||
|
|
|
@ -1075,6 +1075,48 @@ class CaseExpressionTests(TestCase):
|
|||
lambda x: (x, x.foo)
|
||||
)
|
||||
|
||||
def test_join_promotion_multiple_annonations(self):
|
||||
o = CaseTestModel.objects.create(integer=1, integer2=1, string='1')
|
||||
# Testing that:
|
||||
# 1. There isn't any object on the remote side of the fk_rel
|
||||
# relation. If the query used inner joins, then the join to fk_rel
|
||||
# would remove o from the results. So, in effect we are testing that
|
||||
# we are promoting the fk_rel join to a left outer join here.
|
||||
# 2. The default value of 3 is generated for the case expression.
|
||||
self.assertQuerysetEqual(
|
||||
CaseTestModel.objects.filter(pk=o.pk).annotate(
|
||||
foo=Case(
|
||||
When(fk_rel__pk=1, then=2),
|
||||
default=3,
|
||||
output_field=models.IntegerField()
|
||||
),
|
||||
bar=Case(
|
||||
When(fk_rel__pk=1, then=4),
|
||||
default=5,
|
||||
output_field=models.IntegerField()
|
||||
),
|
||||
),
|
||||
[(o, 3, 5)],
|
||||
lambda x: (x, x.foo, x.bar)
|
||||
)
|
||||
# Now 2 should be generated, as the fk_rel is null.
|
||||
self.assertQuerysetEqual(
|
||||
CaseTestModel.objects.filter(pk=o.pk).annotate(
|
||||
foo=Case(
|
||||
When(fk_rel__isnull=True, then=2),
|
||||
default=3,
|
||||
output_field=models.IntegerField()
|
||||
),
|
||||
bar=Case(
|
||||
When(fk_rel__isnull=True, then=4),
|
||||
default=5,
|
||||
output_field=models.IntegerField()
|
||||
),
|
||||
),
|
||||
[(o, 2, 4)],
|
||||
lambda x: (x, x.foo, x.bar)
|
||||
)
|
||||
|
||||
def test_m2m_exclude(self):
|
||||
CaseTestModel.objects.create(integer=10, integer2=1, string='1')
|
||||
qs = CaseTestModel.objects.values_list('id', 'integer').annotate(
|
||||
|
|
Loading…
Reference in New Issue