From 883329ecb3b0dc025a2885813a2d1a1624261166 Mon Sep 17 00:00:00 2001
From: Karen Tracey <kmtracey@gmail.com>
Date: Tue, 16 Mar 2010 19:01:40 +0000
Subject: [PATCH] Fixed #12105: Corrected handling of isnull=False lookups in
 admin. Thanks marcob, Travis Cline, gabrielhurley.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12795 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 django/contrib/admin/views/main.py          |  7 +++++++
 tests/regressiontests/admin_views/models.py |  2 +-
 tests/regressiontests/admin_views/tests.py  | 10 ++++++++++
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py
index df0fd9fab4..d34bb1b195 100644
--- a/django/contrib/admin/views/main.py
+++ b/django/contrib/admin/views/main.py
@@ -185,6 +185,13 @@ class ChangeList(object):
             if key.endswith('__in'):
                 lookup_params[key] = value.split(',')
 
+            # if key ends with __isnull, special case '' and false
+            if key.endswith('__isnull'):
+                if value.lower() in ('', 'false'):
+                    lookup_params[key] = False
+                else:
+                    lookup_params[key] = True
+
         # Apply lookup parameters from the query string.
         try:
             qs = qs.filter(**lookup_params)
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
index 80f137ae86..fffc40571e 100644
--- a/tests/regressiontests/admin_views/models.py
+++ b/tests/regressiontests/admin_views/models.py
@@ -27,7 +27,7 @@ class Article(models.Model):
     title = models.CharField(max_length=100)
     content = models.TextField()
     date = models.DateTimeField()
-    section = models.ForeignKey(Section)
+    section = models.ForeignKey(Section, null=True, blank=True)
 
     def __unicode__(self):
         return self.title
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py
index d614ac7c23..10bfff2092 100644
--- a/tests/regressiontests/admin_views/tests.py
+++ b/tests/regressiontests/admin_views/tests.py
@@ -217,6 +217,16 @@ class AdminViewBasicTest(TestCase):
         response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'color__id__exact': 'StringNotInteger!'})
         self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit)
 
+    def testIsNullLookups(self):
+        """Ensure is_null is handled correctly."""
+        Article.objects.create(title="I Could Go Anywhere", content="Versatile", date=datetime.datetime.now())
+        response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit)
+        self.assertTrue('4 articles' in response.content, '"4 articles" missing from response')
+        response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': 'false'})
+        self.assertTrue('3 articles' in response.content, '"3 articles" missing from response')
+        response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': 'true'})
+        self.assertTrue('1 article' in response.content, '"1 article" missing from response')
+
     def testLogoutAndPasswordChangeURLs(self):
         response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit)
         self.failIf('<a href="/test_admin/%s/logout/">' % self.urlbit not in response.content)