diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 616b24957a1..4eed0160e29 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -221,25 +221,25 @@ class ChangeList(object): # for ordering specified on ModelAdmin or model Meta, we don't know # the right column numbers absolutely, because there might be more # than one column associated with that ordering, so we guess. - for f in ordering: - if f.startswith('-'): - f = f[1:] + for field in ordering: + if field.startswith('-'): + field = field[1:] order_type = 'desc' else: order_type = 'asc' - i = None + index = None try: # Search for simply field name first - i = self.list_display.index(f) + index = list(self.list_display).index(field) except ValueError: - # No match, but their might be a match if we take into account - # 'admin_order_field' - for j, attr in enumerate(self.list_display): - if getattr(attr, 'admin_order_field', '') == f: - i = j + # No match, but there might be a match if we take into + # account 'admin_order_field' + for _index, attr in enumerate(self.list_display): + if getattr(attr, 'admin_order_field', '') == field: + index = _index break - if i is not None: - ordering_fields[i] = order_type + if index is not None: + ordering_fields[index] = order_type else: for p in self.params[ORDER_VAR].split('.'): none, pfx, idx = p.rpartition('-') diff --git a/tests/regressiontests/admin_changelist/admin.py b/tests/regressiontests/admin_changelist/admin.py index d1d8e0fd1e5..80bb732eb00 100644 --- a/tests/regressiontests/admin_changelist/admin.py +++ b/tests/regressiontests/admin_changelist/admin.py @@ -4,7 +4,7 @@ from django.contrib import admin from django.core.paginator import Paginator from .models import (Child, Parent, Genre, Band, Musician, Group, Quartet, - Membership, ChordsMusician, ChordsBand, Invitation) + Membership, ChordsMusician, ChordsBand, Invitation, Swallow) site = admin.AdminSite(name="admin") @@ -75,3 +75,9 @@ class DynamicListDisplayLinksChildAdmin(admin.ModelAdmin): return ['age'] site.register(Child, DynamicListDisplayChildAdmin) + +class SwallowAdmin(admin.ModelAdmin): + actions = None # prevent ['action_checkbox'] + list(list_display) + list_display = ('origin', 'load', 'speed') + +site.register(Swallow, SwallowAdmin) diff --git a/tests/regressiontests/admin_changelist/models.py b/tests/regressiontests/admin_changelist/models.py index eed3f68508e..97080fb5481 100644 --- a/tests/regressiontests/admin_changelist/models.py +++ b/tests/regressiontests/admin_changelist/models.py @@ -49,3 +49,11 @@ class Invitation(models.Model): player = models.ForeignKey(ChordsMusician) band = models.ForeignKey(ChordsBand) instrument = models.CharField(max_length=15) + +class Swallow(models.Model): + origin = models.CharField(max_length=255) + load = models.FloatField() + speed = models.FloatField() + + class Meta: + ordering = ('speed', 'load') diff --git a/tests/regressiontests/admin_changelist/tests.py b/tests/regressiontests/admin_changelist/tests.py index 92928955526..b422519bfb5 100644 --- a/tests/regressiontests/admin_changelist/tests.py +++ b/tests/regressiontests/admin_changelist/tests.py @@ -11,9 +11,10 @@ from django.test.client import RequestFactory from .admin import (ChildAdmin, QuartetAdmin, BandAdmin, ChordsBandAdmin, GroupAdmin, ParentAdmin, DynamicListDisplayChildAdmin, DynamicListDisplayLinksChildAdmin, CustomPaginationAdmin, - FilteredChildAdmin, CustomPaginator, site as custom_site) + FilteredChildAdmin, CustomPaginator, site as custom_site, + SwallowAdmin) from .models import (Child, Parent, Genre, Band, Musician, Group, Quartet, - Membership, ChordsMusician, ChordsBand, Invitation) + Membership, ChordsMusician, ChordsBand, Invitation, Swallow) class ChangeListTests(TestCase): @@ -22,6 +23,14 @@ class ChangeListTests(TestCase): def setUp(self): self.factory = RequestFactory() + def _create_superuser(self, username): + return User.objects.create(username=username, is_superuser=True) + + def _mocked_authenticated_request(self, url, user): + request = self.factory.get(url) + request.user = user + return request + def test_select_related_preserved(self): """ Regression test for #10348: ChangeList.get_query_set() shouldn't @@ -323,21 +332,12 @@ class ChangeListTests(TestCase): for i in range(10): Child.objects.create(name='child %s' % i, parent=parent) - user_noparents = User.objects.create( - username='noparents', - is_superuser=True) - user_parents = User.objects.create( - username='parents', - is_superuser=True) - - def _mocked_authenticated_request(user): - request = self.factory.get('/child/') - request.user = user - return request + user_noparents = self._create_superuser('noparents') + user_parents = self._create_superuser('parents') # Test with user 'noparents' m = custom_site._registry[Child] - request = _mocked_authenticated_request(user_noparents) + request = self._mocked_authenticated_request('/child/', user_noparents) response = m.changelist_view(request) self.assertNotContains(response, 'Parent object') @@ -348,7 +348,7 @@ class ChangeListTests(TestCase): # Test with user 'parents' m = DynamicListDisplayChildAdmin(Child, admin.site) - request = _mocked_authenticated_request(user_parents) + request = self._mocked_authenticated_request('/child/', user_parents) response = m.changelist_view(request) self.assertContains(response, 'Parent object') @@ -362,7 +362,7 @@ class ChangeListTests(TestCase): # Test default implementation custom_site.register(Child, ChildAdmin) m = custom_site._registry[Child] - request = _mocked_authenticated_request(user_noparents) + request = self._mocked_authenticated_request('/child/', user_noparents) response = m.changelist_view(request) self.assertContains(response, 'Parent object') @@ -402,17 +402,9 @@ class ChangeListTests(TestCase): for i in range(1, 10): Child.objects.create(id=i, name='child %s' % i, parent=parent, age=i) - superuser = User.objects.create( - username='superuser', - is_superuser=True) - - def _mocked_authenticated_request(user): - request = self.factory.get('/child/') - request.user = user - return request - m = DynamicListDisplayLinksChildAdmin(Child, admin.site) - request = _mocked_authenticated_request(superuser) + superuser = self._create_superuser('superuser') + request = self._mocked_authenticated_request('/child/', superuser) response = m.changelist_view(request) for i in range(1, 10): self.assertContains(response, '%s' % (i, i)) @@ -420,4 +412,21 @@ class ChangeListTests(TestCase): list_display = m.get_list_display(request) list_display_links = m.get_list_display_links(request, list_display) self.assertEqual(list_display, ('parent', 'name', 'age')) - self.assertEqual(list_display_links, ['age']) \ No newline at end of file + self.assertEqual(list_display_links, ['age']) + + def test_tuple_list_display(self): + """ + Regression test for #17128 + (ChangeList failing under Python 2.5 after r16319) + """ + swallow = Swallow.objects.create( + origin='Africa', load='12.34', speed='22.2') + model_admin = SwallowAdmin(Swallow, admin.site) + superuser = self._create_superuser('superuser') + request = self._mocked_authenticated_request('/swallow/', superuser) + response = model_admin.changelist_view(request) + # just want to ensure it doesn't blow up during rendering + self.assertContains(response, unicode(swallow.origin)) + self.assertContains(response, unicode(swallow.load)) + self.assertContains(response, unicode(swallow.speed)) +