Ticket #17198: 17198.changelist-order.2.diff
File 17198.changelist-order.2.diff, 11.5 KB (added by , 13 years ago) |
---|
-
django/contrib/admin/views/main.py
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 32113f5..acd5106 100644
a b class ChangeList(object): 66 66 self.list_editable = () 67 67 else: 68 68 self.list_editable = list_editable 69 self.ordering = self.get_ordering(request)70 69 self.query = request.GET.get(SEARCH_VAR, '') 71 70 self.query_set = self.get_query_set(request) 72 71 self.get_results(request) … … class ChangeList(object): 218 217 attr = getattr(self.model, field_name) 219 218 return getattr(attr, 'admin_order_field', None) 220 219 221 def get_ordering(self, request ):220 def get_ordering(self, request, queryset): 222 221 params = self.params 223 # For ordering, first check the if exists the "get_ordering" method 224 # in model admin, then check "ordering" parameter in the admin 225 # options, then check the object's default ordering. Finally, a 222 # For ordering, first check the "get_ordering" method in model admin, 223 # then check the object's default ordering. Finally, a 226 224 # manually-specified ordering from the query string overrides anything. 227 ordering = self.model_admin.get_ordering(request) or self._get_default_ordering() 225 ordering = list(self.model_admin.get_ordering(request) 226 or self._get_default_ordering()) 228 227 if ORDER_VAR in params: 229 228 # Clear ordering and used params 230 229 ordering = [] … … class ChangeList(object): 239 238 ordering.append(pfx + order_field) 240 239 except (IndexError, ValueError): 241 240 continue # Invalid ordering specified, skip it. 241 242 # Add the given query's ordering fields, if any. 243 ordering.extend(queryset.query.order_by) 244 245 # Ensure that the primary key is systematically present in the list of 246 # ordering fields so we can guarantee a deterministic order. 247 pk_name = self.lookup_opts.pk.name 248 if not (set(ordering) & set(['pk', '-pk', pk_name, '-' + pk_name])): 249 # The two sets do not intersect, meaning the pk isn't present. So 250 # we add it. 251 ordering.append('pk') 252 242 253 return ordering 243 254 244 255 def get_ordering_field_columns(self): … … class ChangeList(object): 322 333 break 323 334 324 335 # Set ordering. 325 if self.ordering:326 qs = qs.order_by(*self.ordering)336 ordering = self.get_ordering(request, qs) 337 qs = qs.order_by(*ordering) 327 338 328 339 # Apply keyword searches. 329 340 def construct_search(field_name): -
tests/regressiontests/admin_changelist/models.py
diff --git a/tests/regressiontests/admin_changelist/models.py b/tests/regressiontests/admin_changelist/models.py index 97080fb..efa392a 100644
a b class Swallow(models.Model): 57 57 58 58 class Meta: 59 59 ordering = ('speed', 'load') 60 61 62 class UnorderedObject(models.Model): 63 """ 64 Model without any defined `Meta.ordering`. 65 Refs #17198. 66 """ 67 name = models.CharField(max_length=255) 68 bool = models.BooleanField(default=True) 69 No newline at end of file -
tests/regressiontests/admin_changelist/tests.py
diff --git a/tests/regressiontests/admin_changelist/tests.py b/tests/regressiontests/admin_changelist/tests.py index b422519..84cad61 100644
a b from .admin import (ChildAdmin, QuartetAdmin, BandAdmin, ChordsBandAdmin, 14 14 FilteredChildAdmin, CustomPaginator, site as custom_site, 15 15 SwallowAdmin) 16 16 from .models import (Child, Parent, Genre, Band, Musician, Group, Quartet, 17 Membership, ChordsMusician, ChordsBand, Invitation, Swallow) 17 Membership, ChordsMusician, ChordsBand, Invitation, Swallow, 18 UnorderedObject) 18 19 19 20 20 21 class ChangeListTests(TestCase): … … class ChangeListTests(TestCase): 430 431 self.assertContains(response, unicode(swallow.load)) 431 432 self.assertContains(response, unicode(swallow.speed)) 432 433 434 def test_default_ordering_by_pk(self): 435 """ 436 Ensure that the primary key is systematically used in the ordering of 437 the changelist's results to guarantee a deterministic order. 438 Refs #17198. 439 """ 440 superuser = self._create_superuser('superuser') 441 for counter in range(1, 51): 442 UnorderedObject.objects.create( 443 id=counter, name='Unordered object #%s' % counter, bool=True) 444 445 class UnorderedObjectAdmin(admin.ModelAdmin): 446 list_per_page = 10 447 list_display = ['name'] 448 449 def check_results_order(reverse=False): 450 admin.site.register(UnorderedObject, UnorderedObjectAdmin) 451 model_admin = UnorderedObjectAdmin(UnorderedObject, admin.site) 452 counter = 51 if reverse else 0 453 for page in range (0, 5): 454 request = self._mocked_authenticated_request('/unorderedobject/?p=%s' % page, superuser) 455 response = model_admin.changelist_view(request) 456 for result in response.context_data['cl'].result_list: 457 counter += -1 if reverse else 1 458 self.assertEqual(result.id, counter) 459 admin.site.unregister(UnorderedObject) 460 461 # When no order is defined at all 462 check_results_order() 463 464 # When an order is defined 465 UnorderedObjectAdmin.ordering = ['bool'] 466 check_results_order() 467 468 # When an order is defined, including the pk itself 469 UnorderedObjectAdmin.ordering = ['bool', '-pk'] 470 check_results_order(reverse=True) 471 UnorderedObjectAdmin.ordering = ['bool', 'pk'] 472 check_results_order() 473 UnorderedObjectAdmin.ordering = ['-id', 'bool'] 474 check_results_order(reverse=True) 475 UnorderedObjectAdmin.ordering = ['id', 'bool'] 476 check_results_order() 477 No newline at end of file -
tests/regressiontests/admin_views/admin.py
diff --git a/tests/regressiontests/admin_views/admin.py b/tests/regressiontests/admin_views/admin.py index b10d178..d960749 100644
a b from .models import (Article, Chapter, Account, Media, Child, Parent, Picture, 26 26 CoverLetter, Story, OtherStory, Book, Promo, ChapterXtra1, Pizza, Topping, 27 27 Album, Question, Answer, ComplexSortedPerson, PrePopulatedPostLargeSlug, 28 28 AdminOrderedField, AdminOrderedModelMethod, AdminOrderedAdminMethod, 29 AdminOrderedCallable, Report, Color2, MainPrepopulated, RelatedPrepopulated) 29 AdminOrderedCallable, Report, Color2, UnorderedObject, MainPrepopulated, 30 RelatedPrepopulated) 30 31 31 32 32 33 def callable_year(dt_value): … … class MainPrepopulatedAdmin(admin.ModelAdmin): 562 563 'slug2': ['status', 'name']} 563 564 564 565 566 class UnorderedObjectAdmin(admin.ModelAdmin): 567 list_display = ['name'] 568 list_editable = ['name'] 569 list_per_page = 2 570 565 571 566 572 567 573 site = admin.AdminSite(name="admin") … … site.register(Story, StoryAdmin) 609 615 site.register(OtherStory, OtherStoryAdmin) 610 616 site.register(Report, ReportAdmin) 611 617 site.register(MainPrepopulated, MainPrepopulatedAdmin) 618 site.register(UnorderedObject, UnorderedObjectAdmin) 612 619 613 620 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2. 614 621 # That way we cover all four cases: -
tests/regressiontests/admin_views/models.py
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py index cf2896f..c8cd0e8 100644
a b class RelatedPrepopulated(models.Model): 596 596 choices=(('option one', 'Option One'), 597 597 ('option two', 'Option Two'))) 598 598 slug1 = models.SlugField(max_length=50) 599 slug2 = models.SlugField(max_length=60) 600 No newline at end of file 599 slug2 = models.SlugField(max_length=60) 600 601 602 class UnorderedObject(models.Model): 603 """ 604 Model without any defined `Meta.ordering`. 605 Refs #16819. 606 """ 607 name = models.CharField(max_length=255) 608 bool = models.BooleanField(default=True) 609 No newline at end of file -
tests/regressiontests/admin_views/tests.py
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index dc8f29a..9e12131 100755
a b from django.core.exceptions import SuspiciousOperation 12 12 from django.core.files import temp as tempfile 13 13 from django.core.urlresolvers import reverse 14 14 # Register auth models with the admin. 15 from django.contrib import admin 15 16 from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME 16 17 from django.contrib.admin.models import LogEntry, DELETION 17 18 from django.contrib.admin.sites import LOGIN_FORM_KEY … … from .models import (Article, BarAccount, CustomArticle, EmptyModel, FooAccount, 41 42 FoodDelivery, RowLevelChangePermissionModel, Paper, CoverLetter, Story, 42 43 OtherStory, ComplexSortedPerson, Parent, Child, AdminOrderedField, 43 44 AdminOrderedModelMethod, AdminOrderedAdminMethod, AdminOrderedCallable, 44 Report, MainPrepopulated, RelatedPrepopulated )45 Report, MainPrepopulated, RelatedPrepopulated, UnorderedObject) 45 46 46 47 47 48 ERROR_MESSAGE = "Please enter the correct username and password \ … … class AdminViewBasicTest(TestCase): 272 273 ) 273 274 274 275 def testChangeListSortingPreserveQuerySetOrdering(self): 275 # If no ordering on ModelAdmin, or query string, the underlying order of 276 # the queryset should not be changed. 277 276 """ 277 If no ordering is defined in `ModelAdmin.ordering` or in the query 278 string, then the underlying order of the queryset should not be 279 changed, even if it is defined in `Modeladmin.queryset()`. 280 Refs #11868, #7309. 281 """ 278 282 p1 = Person.objects.create(name="Amy", gender=1, alive=True, age=80) 279 283 p2 = Person.objects.create(name="Bob", gender=1, alive=True, age=70) 280 284 p3 = Person.objects.create(name="Chris", gender=2, alive=False, age=60) … … class AdminViewListEditable(TestCase): 1881 1885 self.assertEqual(Category.objects.get(id=3).order, 1) 1882 1886 self.assertEqual(Category.objects.get(id=4).order, 0) 1883 1887 1888 def test_list_editable_ordering_default(self): 1889 """ 1890 Ensure that the list_editable items on the changelist are ordered 1891 in a deterministic order and without raising exceptions, even when 1892 no default ordering is explicitly defined. 1893 Refs #16819. 1894 """ 1895 UnorderedObject.objects.create(id=1, name='Unordered object #1') 1896 UnorderedObject.objects.create(id=2, name='Unordered object #2') 1897 UnorderedObject.objects.create(id=3, name='Unordered object #3') 1898 response = self.client.get('/test_admin/admin/admin_views/unorderedobject/') 1899 self.assertContains(response, 'Unordered object #1') 1900 self.assertContains(response, 'Unordered object #2') 1901 self.assertNotContains(response, 'Unordered object #3') 1902 response = self.client.get('/test_admin/admin/admin_views/unorderedobject/?p=1') 1903 self.assertNotContains(response, 'Unordered object #1') 1904 self.assertNotContains(response, 'Unordered object #2') 1905 self.assertContains(response, 'Unordered object #3') 1906 1884 1907 def test_list_editable_action_submit(self): 1885 1908 # List editable changes should not be executed if the action "Go" button is 1886 1909 # used to submit the form.