1
0
mirror of https://github.com/django/django.git synced 2025-10-31 09:41:08 +00:00

Fixed #11868 - Multiple sort in admin changelist.

Many thanks to bendavis78 for the initial patch, and for input from others.

Also fixed #7309. If people were relying on the undocumented default ordering
applied by the admin before, they will need to add 'ordering = ["-pk"]' to
their ModelAdmin.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16316 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Luke Plant
2011-06-02 16:18:47 +00:00
parent 78b37975c9
commit 5434ce231d
11 changed files with 323 additions and 71 deletions

View File

@@ -67,11 +67,11 @@ class CustomUserAdmin(UserAdmin):
class BookAdmin(ModelAdmin):
list_filter = ('year', 'author', 'contributors', 'is_best_seller', 'date_registered', 'no')
order_by = '-id'
ordering = ('-id',)
class DecadeFilterBookAdmin(ModelAdmin):
list_filter = ('author', DecadeListFilterWithTitleAndParameter)
order_by = '-id'
ordering = ('-id',)
class DecadeFilterBookAdminWithoutTitle(ModelAdmin):
list_filter = (DecadeListFilterWithoutTitle,)

View File

@@ -243,9 +243,6 @@ class Person(models.Model):
def __unicode__(self):
return self.name
class Meta:
ordering = ["id"]
class BasePersonModelFormSet(BaseModelFormSet):
def clean(self):
for person_dict in self.cleaned_data:
@@ -259,13 +256,17 @@ class PersonAdmin(admin.ModelAdmin):
list_editable = ('gender', 'alive')
list_filter = ('gender',)
search_fields = ('^name',)
ordering = ["id"]
save_as = True
def get_changelist_formset(self, request, **kwargs):
return super(PersonAdmin, self).get_changelist_formset(request,
formset=BasePersonModelFormSet, **kwargs)
def queryset(self, request):
# Order by a field that isn't in list display, to be able to test
# whether ordering is preserved.
return super(PersonAdmin, self).queryset(request).order_by('age')
class Persona(models.Model):
"""
@@ -357,6 +358,9 @@ class Media(models.Model):
class Podcast(Media):
release_date = models.DateField()
class Meta:
ordering = ('release_date',) # overridden in PodcastAdmin
class PodcastAdmin(admin.ModelAdmin):
list_display = ('name', 'release_date')
list_editable = ('release_date',)
@@ -795,6 +799,7 @@ class StoryAdmin(admin.ModelAdmin):
list_display_links = ('title',) # 'id' not in list_display_links
list_editable = ('content', )
form = StoryForm
ordering = ["-pk"]
class OtherStory(models.Model):
title = models.CharField(max_length=100)
@@ -804,6 +809,7 @@ class OtherStoryAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'content')
list_display_links = ('title', 'id') # 'id' in list_display_links
list_editable = ('content', )
ordering = ["-pk"]
admin.site.register(Article, ArticleAdmin)
admin.site.register(CustomArticle, CustomArticleAdmin)

View File

@@ -32,7 +32,7 @@ from django.utils import unittest
# local test models
from models import (Article, BarAccount, CustomArticle, EmptyModel,
FooAccount, Gallery, GalleryAdmin, ModelWithStringPrimaryKey,
FooAccount, Gallery, PersonAdmin, ModelWithStringPrimaryKey,
Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast,
Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit,
Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee,
@@ -204,7 +204,7 @@ class AdminViewBasicTest(TestCase):
Ensure we can sort on a list_display field that is a callable
(column 2 is callable_year in ArticleAdmin)
"""
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'ot': 'asc', 'o': 2})
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'o': 2})
self.assertEqual(response.status_code, 200)
self.assertTrue(
response.content.index('Oldest content') < response.content.index('Middle content') and
@@ -217,7 +217,7 @@ class AdminViewBasicTest(TestCase):
Ensure we can sort on a list_display field that is a Model method
(colunn 3 is 'model_year' in ArticleAdmin)
"""
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'ot': 'dsc', 'o': 3})
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'o': '-3'})
self.assertEqual(response.status_code, 200)
self.assertTrue(
response.content.index('Newest content') < response.content.index('Middle content') and
@@ -230,7 +230,7 @@ class AdminViewBasicTest(TestCase):
Ensure we can sort on a list_display field that is a ModelAdmin method
(colunn 4 is 'modeladmin_year' in ArticleAdmin)
"""
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'ot': 'asc', 'o': 4})
response = self.client.get('/test_admin/%s/admin_views/article/' % self.urlbit, {'o': '4'})
self.assertEqual(response.status_code, 200)
self.assertTrue(
response.content.index('Oldest content') < response.content.index('Middle content') and
@@ -238,6 +238,81 @@ class AdminViewBasicTest(TestCase):
"Results of sorting on ModelAdmin method are out of order."
)
def testChangeListSortingMultiple(self):
p1 = Person.objects.create(name="Chris", gender=1, alive=True)
p2 = Person.objects.create(name="Chris", gender=2, alive=True)
p3 = Person.objects.create(name="Bob", gender=1, alive=True)
link = '<a href="%s/'
# Sort by name, gender
# This hard-codes the URL because it'll fail if it runs against the
# 'admin2' custom admin (which doesn't have the Person model).
response = self.client.get('/test_admin/admin/admin_views/person/', {'o': '1.2'})
self.assertEqual(response.status_code, 200)
self.assertTrue(
response.content.index(link % p3.id) < response.content.index(link % p1.id) and
response.content.index(link % p1.id) < response.content.index(link % p2.id)
)
# Sort by gender descending, name
response = self.client.get('/test_admin/admin/admin_views/person/', {'o': '-2.1'})
self.assertEqual(response.status_code, 200)
self.assertTrue(
response.content.index(link % p2.id) < response.content.index(link % p3.id) and
response.content.index(link % p3.id) < response.content.index(link % p1.id)
)
def testChangeListSortingPreserveQuerySetOrdering(self):
# If no ordering on ModelAdmin, or query string, the underlying order of
# the queryset should not be changed.
p1 = Person.objects.create(name="Amy", gender=1, alive=True, age=80)
p2 = Person.objects.create(name="Bob", gender=1, alive=True, age=70)
p3 = Person.objects.create(name="Chris", gender=2, alive=False, age=60)
link = '<a href="%s/'
# This hard-codes the URL because it'll fail if it runs against the
# 'admin2' custom admin (which doesn't have the Person model).
response = self.client.get('/test_admin/admin/admin_views/person/', {})
self.assertEqual(response.status_code, 200)
self.assertTrue(
response.content.index(link % p3.id) < response.content.index(link % p2.id) and
response.content.index(link % p2.id) < response.content.index(link % p1.id)
)
def testChangeListSortingModelMeta(self):
# Test ordering on Model Meta is respected
l1 = Language.objects.create(iso='ur', name='Urdu')
l2 = Language.objects.create(iso='ar', name='Arabic')
link = '<a href="%s/'
response = self.client.get('/test_admin/admin/admin_views/language/', {})
self.assertEqual(response.status_code, 200)
self.assertTrue(
response.content.index(link % l2.pk) < response.content.index(link % l1.pk)
)
# Test we can override with query string
response = self.client.get('/test_admin/admin/admin_views/language/', {'o':'-1'})
self.assertEqual(response.status_code, 200)
self.assertTrue(
response.content.index(link % l1.pk) < response.content.index(link % l2.pk)
)
def testChangeListSortingModelAdmin(self):
# Test ordering on Model Admin is respected, and overrides Model Meta
dt = datetime.datetime.now()
p1 = Podcast.objects.create(name="A", release_date=dt)
p2 = Podcast.objects.create(name="B", release_date=dt - datetime.timedelta(10))
link = '<a href="%s/'
response = self.client.get('/test_admin/admin/admin_views/podcast/', {})
self.assertEqual(response.status_code, 200)
self.assertTrue(
response.content.index(link % p1.pk) < response.content.index(link % p2.pk)
)
def testLimitedFilter(self):
"""Ensure admin changelist filters do not contain objects excluded via limit_choices_to.
This also tests relation-spanning filters (e.g. 'color__value').
@@ -1956,7 +2031,7 @@ class AdminActionsTest(TestCase):
'action' : 'external_mail',
'index': 0,
}
url = '/test_admin/admin/admin_views/externalsubscriber/?ot=asc&o=1'
url = '/test_admin/admin/admin_views/externalsubscriber/?o=1'
response = self.client.post(url, action_data)
self.assertRedirects(response, url)