Ticket #17522: r17364-admin-ordering-validation.diff
File r17364-admin-ordering-validation.diff, 6.7 KB (added by , 13 years ago) |
---|
-
docs/ref/contrib/admin/index.txt
732 732 733 733 Set ``ordering`` to specify how lists of objects should be ordered in the 734 734 Django admin views. This should be a list or tuple in the same format as a 735 model's :attr:`~django.db.models.Options.ordering` parameter. 735 model's :attr:`~django.db.models.Options.ordering` parameter. In addition 736 to field names, ``ordering`` may contain the names of methods of the model 737 or admin class which define the ``admin_order_field`` attribute (cf. 738 :attr:`~ModelAdmin.list_display`). 736 739 737 740 If this isn't provided, the Django admin will use the model's default 738 741 ordering. -
tests/regressiontests/admin_validation/tests.py
4 4 from django.contrib import admin 5 5 from django.contrib.admin.validation import validate, validate_inline 6 6 from django.core.exceptions import ImproperlyConfigured 7 from django.db.models import Count 7 8 from django.test import TestCase 8 9 9 10 from .models import Song, Book, Album, TwoAlbumFKAndAnE, State, City … … 281 282 fields = ['extra_data', 'title'] 282 283 283 284 validate(FieldsOnFormOnlyAdmin, Song) 285 286 def test_ordering_regular_field(self): 287 """ 288 Ordering with proper field must succeed. 289 """ 290 class SongAdmin(admin.ModelAdmin): 291 ordering = ('title',) 292 validate(SongAdmin, Song) 293 294 def test_ordering_nonexisting_field(self): 295 """ 296 Ordering for an unknown field must fail. 297 """ 298 class SongAdmin(admin.ModelAdmin): 299 ordering = ('spam',) 300 self.assertRaisesMessage(ImproperlyConfigured, 301 "'SongAdmin.ordering[0]' refers to field 'spam' that is missing from model 'admin_validation.Song'.", 302 validate, 303 SongAdmin, Song) 304 305 def test_ordering_readonly_method(self): 306 """ 307 Ordering for methods that do not specify admin_order_field 308 must fail. 309 """ 310 class ModelSongAdmin(admin.ModelAdmin): 311 ordering = ('readonly_method_on_model',) 312 self.assertRaisesMessage(ImproperlyConfigured, 313 "'ModelSongAdmin.ordering[0]' refers to method 'readonly_method_on_model' with admin_order_field unset.", 314 validate, 315 ModelSongAdmin, Song) 316 317 class AdminSongAdmin(admin.ModelAdmin): 318 ordering = ('readonly_method_on_admin',) 319 def readonly_method_on_admin(self, song): 320 pass 321 self.assertRaisesMessage(ImproperlyConfigured, 322 "'AdminSongAdmin.ordering[0]' refers to method 'readonly_method_on_admin' with admin_order_field unset.", 323 validate, 324 AdminSongAdmin, Song) 325 326 def test_ordering_sortable_method_field(self): 327 """ 328 Ordering for methods with admin_order_field set to a proper 329 field must succeed. 330 """ 331 class ModelSongAdmin(admin.ModelAdmin): 332 ordering = ('sortable_method_on_model',) 333 validate(ModelSongAdmin, Song) 334 335 class AdminSongAdmin(admin.ModelAdmin): 336 ordering = ('sortable_method_on_admin',) 337 def sortable_method_on_admin(self, song): 338 pass 339 sortable_method_on_admin.admin_order_field = 'title' 340 validate(AdminSongAdmin, Song) 341 342 def test_ordering_sortable_method_queryset(self): 343 """ 344 Ordering for methods with admin_order_field set to name of 345 an additional field (e.g. annotation) returned by a custom 346 queryset must succeed. 347 """ 348 class AlbumAdmin(admin.ModelAdmin): 349 ordering = ('advanced_sortable_method_on_admin',) 350 def queryset(self, request): 351 return Album.objects.annotate(songs_count=Count('song_set')) 352 def advanced_sortable_method_on_admin(self, album): 353 pass 354 advanced_sortable_method_on_admin.admin_order_field = 'songs_count' 355 validate(AlbumAdmin, Album) -
tests/regressiontests/admin_validation/models.py
11 11 12 12 class Song(models.Model): 13 13 title = models.CharField(max_length=150) 14 album = models.ForeignKey(Album )14 album = models.ForeignKey(Album, related_name="song_set") 15 15 original_release = models.DateField(editable=False) 16 16 17 17 class Meta: … … 24 24 # does nothing 25 25 pass 26 26 27 def sortable_method_on_model(self): 28 pass 29 sortable_method_on_model.admin_order_field = 'title' 27 30 31 28 32 class TwoAlbumFKAndAnE(models.Model): 29 33 album1 = models.ForeignKey(Album, related_name="album1_set") 30 34 album2 = models.ForeignKey(Album, related_name="album2_set") -
django/contrib/admin/validation.py
154 154 continue 155 155 if field.startswith('-'): 156 156 field = field[1:] 157 # Check whether `field` is a name of a non-field that 158 # allows for sorting, i.e. name of a method on either 159 # the admin cls or model with admin_order_field set. 160 attr = (getattr(cls, field, None) or 161 getattr(model, field, None)) 162 if callable(attr): 163 if not hasattr(attr, 'admin_order_field'): 164 # Found method but no admin_order_field. 165 raise ImproperlyConfigured("'%s.%s' refers " 166 "to method '%s' with admin_order_field unset." 167 % (cls.__name__, 'ordering[%d]' % idx, field)) 168 # No further checks for methods with 169 # admin_order_field. In particular, we do not enforce 170 # admin_order_field to refer to an actual model field: 171 # it might also be an annotation returned by the model 172 # admin's custom queryset() method etc. 173 continue 157 174 # Skip ordering in the format field1__field2 (FIXME: checking 158 175 # this format would be nice, but it's a little fiddly). 159 176 if '__' in field: