From e41df5adccef0e32d4b8b877ec83e9dd271c1ccf Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Thu, 26 Jun 2008 05:34:26 +0000 Subject: [PATCH] Fixed #7076 -- Include NULL values when excluding non-NULL items. Based on a patch from emulbreh. git-svn-id: http://code.djangoproject.com/svn/django/trunk@7760 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/sql/query.py | 26 +++++++++++++++++-------- tests/regressiontests/queries/models.py | 6 ++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index e3e3585a8e..b30c6a355c 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -1045,17 +1045,27 @@ class Query(object): self.promote_alias(table) self.where.add((alias, col, field, lookup_type, value), connector) + if negate: for alias in join_list: self.promote_alias(alias) - if final > 1 and lookup_type != 'isnull': - for alias in join_list: - if self.alias_map[alias] == self.LOUTER: - j_col = self.alias_map[alias][RHS_JOIN_COL] - entry = Node([(alias, j_col, None, 'isnull', True)]) - entry.negate() - self.where.add(entry, AND) - break + if lookup_type != 'isnull': + if final > 1: + for alias in join_list: + if self.alias_map[alias][JOIN_TYPE] == self.LOUTER: + j_col = self.alias_map[alias][RHS_JOIN_COL] + entry = Node([(alias, j_col, None, 'isnull', True)]) + entry.negate() + self.where.add(entry, AND) + break + elif not (lookup_type == 'in' and not value): + # Leaky abstraction artifact: We have to specifically + # exclude the "foo__in=[]" case from this handling, because + # it's short-circuited in the Where class. + entry = Node([(alias, col, field, 'isnull', True)]) + entry.negate() + self.where.add(entry, AND) + if can_reuse is not None: can_reuse.update(join_list) diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py index 8059798f86..d7c8fba9c6 100644 --- a/tests/regressiontests/queries/models.py +++ b/tests/regressiontests/queries/models.py @@ -756,5 +756,11 @@ select_related(). We used to return the parent's Detail record here by mistake. >>> obj.person.details.data u'd2' +Bug #7076 -- excluding shouldn't eliminate NULL entries. +>>> Item.objects.exclude(modified=time1).order_by('name') +[, , ] +>>> Tag.objects.exclude(parent__name=t1.name) +[, , ] + """}