mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #20182 - admin lookup should treat 0 as False for __isnull
Thanks Benjie Chen.
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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) | ||||
| @@ -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, | ||||
| @@ -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): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user