Loading django/db/models/query_utils.py +6 −1 Original line number Diff line number Diff line Loading @@ -87,7 +87,12 @@ class Q(tree.Node): return clone def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False): clause, _ = query._add_q(self, reuse, allow_joins=allow_joins) # 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) joins_to_promote = [j for j in joins if j not in joins_before] query.promote_joins(joins_to_promote) return clause @classmethod Loading docs/releases/1.8.2.txt +4 −0 Original line number Diff line number Diff line Loading @@ -13,3 +13,7 @@ Bugfixes * Fixed crash when reusing the same ``Case`` instance in a query (:ticket:`24752`). * Corrected join promotion for ``Case`` expressions. For example, annotating a query with a ``Case`` expression could unexpectedly filter out results (:ticket:`24766`). tests/expressions_case/tests.py +32 −0 Original line number Diff line number Diff line Loading @@ -1016,6 +1016,38 @@ class CaseExpressionTests(TestCase): transform=attrgetter('integer', 'test') ) def test_join_promotion(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() ), ), [(o, 3)], lambda x: (x, x.foo) ) # 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() ), ), [(o, 2)], lambda x: (x, x.foo) ) class CaseDocumentationExamples(TestCase): @classmethod Loading Loading
django/db/models/query_utils.py +6 −1 Original line number Diff line number Diff line Loading @@ -87,7 +87,12 @@ class Q(tree.Node): return clone def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False): clause, _ = query._add_q(self, reuse, allow_joins=allow_joins) # 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) joins_to_promote = [j for j in joins if j not in joins_before] query.promote_joins(joins_to_promote) return clause @classmethod Loading
docs/releases/1.8.2.txt +4 −0 Original line number Diff line number Diff line Loading @@ -13,3 +13,7 @@ Bugfixes * Fixed crash when reusing the same ``Case`` instance in a query (:ticket:`24752`). * Corrected join promotion for ``Case`` expressions. For example, annotating a query with a ``Case`` expression could unexpectedly filter out results (:ticket:`24766`).
tests/expressions_case/tests.py +32 −0 Original line number Diff line number Diff line Loading @@ -1016,6 +1016,38 @@ class CaseExpressionTests(TestCase): transform=attrgetter('integer', 'test') ) def test_join_promotion(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() ), ), [(o, 3)], lambda x: (x, x.foo) ) # 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() ), ), [(o, 2)], lambda x: (x, x.foo) ) class CaseDocumentationExamples(TestCase): @classmethod Loading