mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.8.x] Fixed #24924 -- Join promotion for multiple Case expressions
Backport of 541f4ea546 from master
			
			
This commit is contained in:
		| @@ -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( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user