From 8ad436636fd385abd144274952b0c066885af042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anssi=20K=C3=A4=C3=A4ri=C3=A4inen?= Date: Wed, 20 Feb 2013 21:52:44 +0200 Subject: [PATCH] [1.5.x] Fixed #19672 -- Error in negated Q() filtering There was a variable overwrite error in negated join filtering. This happened when add_filter() was adding the IS NULL condition to the WHERE clause. This is not a backport from master as there have been some other refactorings which made this patch irrelevant. The patch is from Ian Kelly. --- django/db/models/sql/query.py | 8 ++++---- tests/regressiontests/queries/models.py | 1 + tests/regressiontests/queries/tests.py | 12 ++++++++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 9c2af10e35..e7c8d6caaf 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -1193,15 +1193,15 @@ class Query(object): self.promote_joins(join_list) if lookup_type != 'isnull': if len(join_list) > 1: - for alias in join_list: - if self.alias_map[alias].join_type == self.LOUTER: - j_col = self.alias_map[alias].rhs_join_col + for j_alias in join_list: + if self.alias_map[j_alias].join_type == self.LOUTER: + j_col = self.alias_map[j_alias].rhs_join_col # The join promotion logic should never produce # a LOUTER join for the base join - assert that. assert j_col is not None entry = self.where_class() entry.add( - (Constraint(alias, j_col, None), 'isnull', True), + (Constraint(j_alias, j_col, None), 'isnull', True), AND ) entry.negate() diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py index f0178a0256..4ce696c277 100644 --- a/tests/regressiontests/queries/models.py +++ b/tests/regressiontests/queries/models.py @@ -64,6 +64,7 @@ class Annotation(models.Model): class ExtraInfo(models.Model): info = models.CharField(max_length=100) note = models.ForeignKey(Note) + value = models.IntegerField(null=True) class Meta: ordering = ['info'] diff --git a/tests/regressiontests/queries/tests.py b/tests/regressiontests/queries/tests.py index a6bd2436c1..a2f91e9964 100644 --- a/tests/regressiontests/queries/tests.py +++ b/tests/regressiontests/queries/tests.py @@ -51,8 +51,8 @@ class Queries1Tests(BaseQuerysetTest): # Create these out of order so that sorting by 'id' will be different to sorting # by 'info'. Helps detect some problems later. - self.e2 = ExtraInfo.objects.create(info='e2', note=n2) - e1 = ExtraInfo.objects.create(info='e1', note=self.n1) + self.e2 = ExtraInfo.objects.create(info='e2', note=n2, value=41) + e1 = ExtraInfo.objects.create(info='e1', note=self.n1, value=42) self.a1 = Author.objects.create(name='a1', num=1001, extra=e1) self.a2 = Author.objects.create(name='a2', num=2002, extra=e1) @@ -880,6 +880,14 @@ class Queries1Tests(BaseQuerysetTest): Item.objects.filter(Q(tags__name__in=['t4', 't3'])), [repr(i) for i in Item.objects.filter(~~Q(tags__name__in=['t4', 't3']))]) + def test_ticket19672(self): + self.assertQuerysetEqual( + Report.objects.filter(Q(creator__isnull=False) & + ~Q(creator__extra__value=41)), + [''] + ) + + class Queries2Tests(TestCase): def setUp(self): Number.objects.create(num=4)