Fixed #12875 -- Added get_ordering to ModelAdmin. Many thanks to Manuel Saelices.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16383 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2011-06-12 13:04:53 +00:00
parent f0adae4c6e
commit f749bb829c
6 changed files with 69 additions and 12 deletions

View File

@ -189,6 +189,12 @@ class BaseModelAdmin(object):
return None return None
declared_fieldsets = property(_declared_fieldsets) declared_fieldsets = property(_declared_fieldsets)
def get_ordering(self, request):
"""
Hook for specifying field ordering.
"""
return self.ordering or () # otherwise we might try to *None, which is bad ;)
def get_readonly_fields(self, request, obj=None): def get_readonly_fields(self, request, obj=None):
""" """
Hook for specifying custom readonly fields. Hook for specifying custom readonly fields.
@ -208,7 +214,7 @@ class BaseModelAdmin(object):
""" """
qs = self.model._default_manager.get_query_set() qs = self.model._default_manager.get_query_set()
# TODO: this should be handled by some parameter to the ChangeList. # TODO: this should be handled by some parameter to the ChangeList.
ordering = self.ordering or () # otherwise we might try to *None, which is bad ;) ordering = self.get_ordering(request)
if ordering: if ordering:
qs = qs.order_by(*ordering) qs = qs.order_by(*ordering)
return qs return qs
@ -260,6 +266,7 @@ class BaseModelAdmin(object):
clean_lookup = LOOKUP_SEP.join(parts) clean_lookup = LOOKUP_SEP.join(parts)
return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
class ModelAdmin(BaseModelAdmin): class ModelAdmin(BaseModelAdmin):
"Encapsulates all admin options and functionality for a given model." "Encapsulates all admin options and functionality for a given model."

View File

@ -76,7 +76,7 @@ class ChangeList(object):
self.list_editable = () self.list_editable = ()
else: else:
self.list_editable = list_editable self.list_editable = list_editable
self.ordering = self.get_ordering() self.ordering = self.get_ordering(request)
self.query = request.GET.get(SEARCH_VAR, '') self.query = request.GET.get(SEARCH_VAR, '')
self.query_set = self.get_query_set(request) self.query_set = self.get_query_set(request)
self.get_results(request) self.get_results(request)
@ -172,12 +172,13 @@ class ChangeList(object):
ordering = self.lookup_opts.ordering ordering = self.lookup_opts.ordering
return ordering return ordering
def get_ordering(self): def get_ordering(self, request):
params = self.params params = self.params
# For ordering, first check the "ordering" parameter in the admin # For ordering, first check the if exists the "get_ordering" method
# in model admin, then check "ordering" parameter in the admin
# options, then check the object's default ordering. Finally, a # options, then check the object's default ordering. Finally, a
# manually-specified ordering from the query string overrides anything. # manually-specified ordering from the query string overrides anything.
ordering = self._get_default_ordering() ordering = self.model_admin.get_ordering(request) or self._get_default_ordering()
if ORDER_VAR in params: if ORDER_VAR in params:
# Clear ordering and used params # Clear ordering and used params

View File

@ -704,6 +704,11 @@ subclass::
If this isn't provided, the Django admin will use the model's default If this isn't provided, the Django admin will use the model's default
ordering. ordering.
.. versionadded:: 1.4
If you need to specify a dynamic order (for example depending on user or
language) you can implement a :meth:`~ModelAdmin.get_ordering` method.
.. versionchanged:: 1.4 .. versionchanged:: 1.4
Django honors all elements in the list/tuple; before 1.4, only the first Django honors all elements in the list/tuple; before 1.4, only the first
@ -957,6 +962,22 @@ templates used by the :class:`ModelAdmin` views:
instance.save() instance.save()
formset.save_m2m() formset.save_m2m()
.. method:: ModelAdmin.get_ordering(self, request)
.. versionadded:: 1.4
The ``get_ordering`` method takes a``request`` as parameter and
is expected to return a ``list`` or ``tuple`` for ordering similiar
to the :attr:`ordering` attribute. For example::
class PersonAdmin(ModelAdmin):
def get_ordering(self, request):
if request.user.is_superuser:
return ['name', 'rank']
else:
return ['name']
.. method:: ModelAdmin.get_readonly_fields(self, request, obj=None) .. method:: ModelAdmin.get_readonly_fields(self, request, obj=None)
.. versionadded:: 1.2 .. versionadded:: 1.2
@ -1053,7 +1074,7 @@ templates used by the :class:`ModelAdmin` views:
.. method:: ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs) .. method:: ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs)
The ``formfield_for_foreignkey`` method on a ``ModelAdmin`` allows you to The ``formfield_for_foreignkey`` method on a ``ModelAdmin`` allows you to
override the default formfield for a foreign key field. For example, to override the default formfield for a foreign keys field. For example, to
return a subset of objects for this foreign key field based on the user:: return a subset of objects for this foreign key field based on the user::
class MyModelAdmin(admin.ModelAdmin): class MyModelAdmin(admin.ModelAdmin):

View File

@ -73,10 +73,12 @@ documentation for :attr:`~django.contrib.admin.ModelAdmin.list_filter`.
Multiple sort in admin interface Multiple sort in admin interface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The admin change list now supports sorting on multiple columns. It respects all The admin change list now supports sorting on multiple columns. It respects
elements of the :attr:`~django.contrib.admin.ModelAdmin.ordering` attribute, and all elements of the :attr:`~django.contrib.admin.ModelAdmin.ordering`
sorting on multiple columns by clicking on headers is designed to work similarly attribute, and sorting on multiple columns by clicking on headers is designed
to how desktop GUIs do it. to work similarly to how desktop GUIs do it. The new hook
:meth:`~django.contrib.admin.ModelAdmin.get_ordering` for specifying the
ordering dynamically (e.g. depending on the request) has also been added.
Tools for cryptographic signing Tools for cryptographic signing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -24,3 +24,11 @@ class SongInlineDefaultOrdering(admin.StackedInline):
class SongInlineNewOrdering(admin.StackedInline): class SongInlineNewOrdering(admin.StackedInline):
model = Song model = Song
ordering = ('duration', ) ordering = ('duration', )
class DynOrderingBandAdmin(admin.ModelAdmin):
def get_ordering(self, request):
if request.user.is_superuser:
return ['rank']
else:
return ['name']

View File

@ -1,7 +1,8 @@
from django.test import TestCase from django.test import TestCase, RequestFactory
from django.contrib.auth.models import User
from django.contrib.admin.options import ModelAdmin from django.contrib.admin.options import ModelAdmin
from models import Band, Song, SongInlineDefaultOrdering, SongInlineNewOrdering from models import Band, Song, SongInlineDefaultOrdering, SongInlineNewOrdering, DynOrderingBandAdmin
class TestAdminOrdering(TestCase): class TestAdminOrdering(TestCase):
""" """
@ -11,6 +12,7 @@ class TestAdminOrdering(TestCase):
""" """
def setUp(self): def setUp(self):
self.request_factory = RequestFactory()
b1 = Band(name='Aerosmith', bio='', rank=3) b1 = Band(name='Aerosmith', bio='', rank=3)
b1.save() b1.save()
b2 = Band(name='Radiohead', bio='', rank=1) b2 = Band(name='Radiohead', bio='', rank=1)
@ -38,6 +40,22 @@ class TestAdminOrdering(TestCase):
names = [b.name for b in ma.queryset(None)] names = [b.name for b in ma.queryset(None)]
self.assertEqual([u'Radiohead', u'Van Halen', u'Aerosmith'], names) self.assertEqual([u'Radiohead', u'Van Halen', u'Aerosmith'], names)
def test_dynamic_ordering(self):
"""
Let's use a custom ModelAdmin that changes the ordering dinamically.
"""
super_user = User.objects.create(username='admin', is_superuser=True)
other_user = User.objects.create(username='other')
request = self.request_factory.get('/')
request.user = super_user
ma = DynOrderingBandAdmin(Band, None)
names = [b.name for b in ma.queryset(request)]
self.assertEqual([u'Radiohead', u'Van Halen', u'Aerosmith'], names)
request.user = other_user
names = [b.name for b in ma.queryset(request)]
self.assertEqual([u'Aerosmith', u'Radiohead', u'Van Halen'], names)
class TestInlineModelAdminOrdering(TestCase): class TestInlineModelAdminOrdering(TestCase):
""" """
Let's make sure that InlineModelAdmin.queryset uses the ordering we define Let's make sure that InlineModelAdmin.queryset uses the ordering we define