Loading django/contrib/admin/util.py +2 −2 Original line number Diff line number Diff line Loading @@ -37,9 +37,9 @@ def prepare_lookup_value(key, value): # if key ends with __in, split parameter into separate values if key.endswith('__in'): value = value.split(',') # if key ends with __isnull, special case '' and false # if key ends with __isnull, special case '' and the string literals 'false' and '0' if key.endswith('__isnull'): if value.lower() in ('', 'false'): if value.lower() in ('', 'false', '0'): value = False else: value = True Loading tests/admin_views/admin.py +1 −1 Original line number Diff line number Diff line Loading @@ -149,7 +149,7 @@ class InquisitionAdmin(admin.ModelAdmin): class SketchAdmin(admin.ModelAdmin): raw_id_fields = ('inquisition',) raw_id_fields = ('inquisition', 'defendant0', 'defendant1') class FabricAdmin(admin.ModelAdmin): Loading tests/admin_views/models.py +3 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ class Thing(models.Model): class Actor(models.Model): name = models.CharField(max_length=50) age = models.IntegerField() title = models.CharField(max_length=50, null=True) def __str__(self): return self.name Loading @@ -158,6 +159,8 @@ class Sketch(models.Model): 'leader__age': 27, 'expected': False, }) defendant0 = models.ForeignKey(Actor, limit_choices_to={'title__isnull': False}, related_name='as_defendant0') defendant1 = models.ForeignKey(Actor, limit_choices_to={'title__isnull': True}, related_name='as_defendant1') def __str__(self): return self.title Loading tests/admin_views/tests.py +51 −2 Original line number Diff line number Diff line Loading @@ -468,8 +468,12 @@ class AdminViewBasicTest(TestCase): self.assertContains(response, '4 articles') response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': 'false'}) self.assertContains(response, '3 articles') response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': '0'}) self.assertContains(response, '3 articles') response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': 'true'}) self.assertContains(response, '1 article') response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': '1'}) self.assertContains(response, '1 article') def testLogoutAndPasswordChangeURLs(self): response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit) Loading Loading @@ -3508,7 +3512,6 @@ class RawIdFieldsTest(TestCase): def test_limit_choices_to(self): """Regression test for 14880""" # This includes tests integers, strings and booleans in the lookup query string actor = Actor.objects.create(name="Palin", age=27) inquisition1 = Inquisition.objects.create(expected=True, leader=actor, Loading @@ -3524,11 +3527,57 @@ class RawIdFieldsTest(TestCase): # Handle relative links popup_url = urljoin(response.request['PATH_INFO'], popup_url) # Get the popup # Get the popup and verify the correct objects show up in the resulting # page. This step also tests integers, strings and booleans in the # lookup query string; in model we define inquisition field to have a # limit_choices_to option that includes a filter on a string field # (inquisition__actor__name), a filter on an integer field # (inquisition__actor__age), and a filter on a boolean field # (inquisition__expected). response2 = self.client.get(popup_url) self.assertContains(response2, "Spain") self.assertNotContains(response2, "England") def test_limit_choices_to_isnull_false(self): """Regression test for 20182""" Actor.objects.create(name="Palin", age=27) Actor.objects.create(name="Kilbraken", age=50, title="Judge") response = self.client.get('/test_admin/admin/admin_views/sketch/add/') # Find the link m = re.search(br'<a href="([^"]*)"[^>]* id="lookup_id_defendant0"', response.content) self.assertTrue(m) # Got a match popup_url = m.groups()[0].decode().replace("&", "&") # Handle relative links popup_url = urljoin(response.request['PATH_INFO'], popup_url) # Get the popup and verify the correct objects show up in the resulting # page. This step tests field__isnull=0 gets parsed correctly from the # lookup query string; in model we define defendant0 field to have a # limit_choices_to option that includes "actor__title__isnull=False". response2 = self.client.get(popup_url) self.assertContains(response2, "Kilbraken") self.assertNotContains(response2, "Palin") def test_limit_choices_to_isnull_true(self): """Regression test for 20182""" Actor.objects.create(name="Palin", age=27) Actor.objects.create(name="Kilbraken", age=50, title="Judge") response = self.client.get('/test_admin/admin/admin_views/sketch/add/') # Find the link m = re.search(br'<a href="([^"]*)"[^>]* id="lookup_id_defendant1"', response.content) self.assertTrue(m) # Got a match popup_url = m.groups()[0].decode().replace("&", "&") # Handle relative links popup_url = urljoin(response.request['PATH_INFO'], popup_url) # Get the popup and verify the correct objects show up in the resulting # page. This step tests field__isnull=1 gets parsed correctly from the # lookup query string; in model we define defendant1 field to have a # limit_choices_to option that includes "actor__title__isnull=True". response2 = self.client.get(popup_url) self.assertNotContains(response2, "Kilbraken") self.assertContains(response2, "Palin") @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) class UserAdminTest(TestCase): Loading Loading
django/contrib/admin/util.py +2 −2 Original line number Diff line number Diff line Loading @@ -37,9 +37,9 @@ def prepare_lookup_value(key, value): # if key ends with __in, split parameter into separate values if key.endswith('__in'): value = value.split(',') # if key ends with __isnull, special case '' and false # if key ends with __isnull, special case '' and the string literals 'false' and '0' if key.endswith('__isnull'): if value.lower() in ('', 'false'): if value.lower() in ('', 'false', '0'): value = False else: value = True Loading
tests/admin_views/admin.py +1 −1 Original line number Diff line number Diff line Loading @@ -149,7 +149,7 @@ class InquisitionAdmin(admin.ModelAdmin): class SketchAdmin(admin.ModelAdmin): raw_id_fields = ('inquisition',) raw_id_fields = ('inquisition', 'defendant0', 'defendant1') class FabricAdmin(admin.ModelAdmin): Loading
tests/admin_views/models.py +3 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ class Thing(models.Model): class Actor(models.Model): name = models.CharField(max_length=50) age = models.IntegerField() title = models.CharField(max_length=50, null=True) def __str__(self): return self.name Loading @@ -158,6 +159,8 @@ class Sketch(models.Model): 'leader__age': 27, 'expected': False, }) defendant0 = models.ForeignKey(Actor, limit_choices_to={'title__isnull': False}, related_name='as_defendant0') defendant1 = models.ForeignKey(Actor, limit_choices_to={'title__isnull': True}, related_name='as_defendant1') def __str__(self): return self.title Loading
tests/admin_views/tests.py +51 −2 Original line number Diff line number Diff line Loading @@ -468,8 +468,12 @@ class AdminViewBasicTest(TestCase): self.assertContains(response, '4 articles') response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': 'false'}) self.assertContains(response, '3 articles') response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': '0'}) self.assertContains(response, '3 articles') response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': 'true'}) self.assertContains(response, '1 article') response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': '1'}) self.assertContains(response, '1 article') def testLogoutAndPasswordChangeURLs(self): response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit) Loading Loading @@ -3508,7 +3512,6 @@ class RawIdFieldsTest(TestCase): def test_limit_choices_to(self): """Regression test for 14880""" # This includes tests integers, strings and booleans in the lookup query string actor = Actor.objects.create(name="Palin", age=27) inquisition1 = Inquisition.objects.create(expected=True, leader=actor, Loading @@ -3524,11 +3527,57 @@ class RawIdFieldsTest(TestCase): # Handle relative links popup_url = urljoin(response.request['PATH_INFO'], popup_url) # Get the popup # Get the popup and verify the correct objects show up in the resulting # page. This step also tests integers, strings and booleans in the # lookup query string; in model we define inquisition field to have a # limit_choices_to option that includes a filter on a string field # (inquisition__actor__name), a filter on an integer field # (inquisition__actor__age), and a filter on a boolean field # (inquisition__expected). response2 = self.client.get(popup_url) self.assertContains(response2, "Spain") self.assertNotContains(response2, "England") def test_limit_choices_to_isnull_false(self): """Regression test for 20182""" Actor.objects.create(name="Palin", age=27) Actor.objects.create(name="Kilbraken", age=50, title="Judge") response = self.client.get('/test_admin/admin/admin_views/sketch/add/') # Find the link m = re.search(br'<a href="([^"]*)"[^>]* id="lookup_id_defendant0"', response.content) self.assertTrue(m) # Got a match popup_url = m.groups()[0].decode().replace("&", "&") # Handle relative links popup_url = urljoin(response.request['PATH_INFO'], popup_url) # Get the popup and verify the correct objects show up in the resulting # page. This step tests field__isnull=0 gets parsed correctly from the # lookup query string; in model we define defendant0 field to have a # limit_choices_to option that includes "actor__title__isnull=False". response2 = self.client.get(popup_url) self.assertContains(response2, "Kilbraken") self.assertNotContains(response2, "Palin") def test_limit_choices_to_isnull_true(self): """Regression test for 20182""" Actor.objects.create(name="Palin", age=27) Actor.objects.create(name="Kilbraken", age=50, title="Judge") response = self.client.get('/test_admin/admin/admin_views/sketch/add/') # Find the link m = re.search(br'<a href="([^"]*)"[^>]* id="lookup_id_defendant1"', response.content) self.assertTrue(m) # Got a match popup_url = m.groups()[0].decode().replace("&", "&") # Handle relative links popup_url = urljoin(response.request['PATH_INFO'], popup_url) # Get the popup and verify the correct objects show up in the resulting # page. This step tests field__isnull=1 gets parsed correctly from the # lookup query string; in model we define defendant1 field to have a # limit_choices_to option that includes "actor__title__isnull=True". response2 = self.client.get(popup_url) self.assertNotContains(response2, "Kilbraken") self.assertContains(response2, "Palin") @override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) class UserAdminTest(TestCase): Loading