Fixed #20182 - admin lookup should treat 0 as False for __isnull
Thanks Benjie Chen.
This commit is contained in:
parent
d194714c0a
commit
0268aba96b
|
@ -37,9 +37,9 @@ def prepare_lookup_value(key, value):
|
||||||
# if key ends with __in, split parameter into separate values
|
# if key ends with __in, split parameter into separate values
|
||||||
if key.endswith('__in'):
|
if key.endswith('__in'):
|
||||||
value = value.split(',')
|
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 key.endswith('__isnull'):
|
||||||
if value.lower() in ('', 'false'):
|
if value.lower() in ('', 'false', '0'):
|
||||||
value = False
|
value = False
|
||||||
else:
|
else:
|
||||||
value = True
|
value = True
|
||||||
|
|
|
@ -149,7 +149,7 @@ class InquisitionAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
class SketchAdmin(admin.ModelAdmin):
|
class SketchAdmin(admin.ModelAdmin):
|
||||||
raw_id_fields = ('inquisition',)
|
raw_id_fields = ('inquisition', 'defendant0', 'defendant1')
|
||||||
|
|
||||||
|
|
||||||
class FabricAdmin(admin.ModelAdmin):
|
class FabricAdmin(admin.ModelAdmin):
|
||||||
|
|
|
@ -137,6 +137,7 @@ class Thing(models.Model):
|
||||||
class Actor(models.Model):
|
class Actor(models.Model):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
age = models.IntegerField()
|
age = models.IntegerField()
|
||||||
|
title = models.CharField(max_length=50, null=True)
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@ -158,6 +159,8 @@ class Sketch(models.Model):
|
||||||
'leader__age': 27,
|
'leader__age': 27,
|
||||||
'expected': False,
|
'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):
|
def __str__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
|
@ -468,8 +468,12 @@ class AdminViewBasicTest(TestCase):
|
||||||
self.assertContains(response, '4 articles')
|
self.assertContains(response, '4 articles')
|
||||||
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': 'false'})
|
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': 'false'})
|
||||||
self.assertContains(response, '3 articles')
|
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'})
|
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'section__isnull': 'true'})
|
||||||
self.assertContains(response, '1 article')
|
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):
|
def testLogoutAndPasswordChangeURLs(self):
|
||||||
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit)
|
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):
|
def test_limit_choices_to(self):
|
||||||
"""Regression test for 14880"""
|
"""Regression test for 14880"""
|
||||||
# This includes tests integers, strings and booleans in the lookup query string
|
|
||||||
actor = Actor.objects.create(name="Palin", age=27)
|
actor = Actor.objects.create(name="Palin", age=27)
|
||||||
inquisition1 = Inquisition.objects.create(expected=True,
|
inquisition1 = Inquisition.objects.create(expected=True,
|
||||||
leader=actor,
|
leader=actor,
|
||||||
|
@ -3524,11 +3527,57 @@ class RawIdFieldsTest(TestCase):
|
||||||
|
|
||||||
# Handle relative links
|
# Handle relative links
|
||||||
popup_url = urljoin(response.request['PATH_INFO'], popup_url)
|
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)
|
response2 = self.client.get(popup_url)
|
||||||
self.assertContains(response2, "Spain")
|
self.assertContains(response2, "Spain")
|
||||||
self.assertNotContains(response2, "England")
|
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',))
|
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
|
||||||
class UserAdminTest(TestCase):
|
class UserAdminTest(TestCase):
|
||||||
|
|
Loading…
Reference in New Issue