Fixed #13862 -- Added an ordering option to InlineModelAdmin and cleaned up documentation for it a bit. Thanks, Simon Meers, rasca and cogat.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14882 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2010-12-12 22:56:01 +00:00
parent 1e7bb904df
commit b3520da9ac
4 changed files with 97 additions and 23 deletions

View File

@ -67,6 +67,7 @@ class BaseModelAdmin(object):
prepopulated_fields = {} prepopulated_fields = {}
formfield_overrides = {} formfield_overrides = {}
readonly_fields = () readonly_fields = ()
ordering = None
def __init__(self): def __init__(self):
overrides = FORMFIELD_FOR_DBFIELD_DEFAULTS.copy() overrides = FORMFIELD_FOR_DBFIELD_DEFAULTS.copy()
@ -189,6 +190,18 @@ class BaseModelAdmin(object):
def get_readonly_fields(self, request, obj=None): def get_readonly_fields(self, request, obj=None):
return self.readonly_fields return self.readonly_fields
def queryset(self, request):
"""
Returns a QuerySet of all model instances that can be edited by the
admin site. This is used by changelist_view.
"""
qs = self.model._default_manager.get_query_set()
# TODO: this should be handled by some parameter to the ChangeList.
ordering = self.ordering or () # otherwise we might try to *None, which is bad ;)
if ordering:
qs = qs.order_by(*ordering)
return qs
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."
@ -202,7 +215,6 @@ class ModelAdmin(BaseModelAdmin):
date_hierarchy = None date_hierarchy = None
save_as = False save_as = False
save_on_top = False save_on_top = False
ordering = None
inlines = [] inlines = []
# Custom templates (designed to be over-ridden in subclasses) # Custom templates (designed to be over-ridden in subclasses)
@ -325,18 +337,6 @@ class ModelAdmin(BaseModelAdmin):
'delete': self.has_delete_permission(request), 'delete': self.has_delete_permission(request),
} }
def queryset(self, request):
"""
Returns a QuerySet of all model instances that can be edited by the
admin site. This is used by changelist_view.
"""
qs = self.model._default_manager.get_query_set()
# TODO: this should be handled by some parameter to the ChangeList.
ordering = self.ordering or () # otherwise we might try to *None, which is bad ;)
if ordering:
qs = qs.order_by(*ordering)
return qs
def get_fieldsets(self, request, obj=None): def get_fieldsets(self, request, obj=None):
"Hook for specifying fieldsets for the add form." "Hook for specifying fieldsets for the add form."
if self.declared_fieldsets: if self.declared_fieldsets:
@ -1257,9 +1257,6 @@ class InlineModelAdmin(BaseModelAdmin):
fields = form.base_fields.keys() + list(self.get_readonly_fields(request, obj)) fields = form.base_fields.keys() + list(self.get_readonly_fields(request, obj))
return [(None, {'fields': fields})] return [(None, {'fields': fields})]
def queryset(self, request):
return self.model._default_manager.all()
class StackedInline(InlineModelAdmin): class StackedInline(InlineModelAdmin):
template = 'admin/edit_inline/stacked.html' template = 'admin/edit_inline/stacked.html'

View File

@ -180,7 +180,7 @@ subclass::
.. versionadded:: 1.2 .. versionadded:: 1.2
``fields`` can contain values defined in ``fields`` can contain values defined in
:attr:`ModelAdmin.readonly_fields` to be displayed as read-only. :attr:`~ModelAdmin.readonly_fields` to be displayed as read-only.
* ``classes`` * ``classes``
A list containing extra CSS classes to apply to the fieldset. A list containing extra CSS classes to apply to the fieldset.
@ -504,8 +504,8 @@ subclass::
.. attribute:: ModelAdmin.ordering .. attribute:: ModelAdmin.ordering
Set ``ordering`` to specify how objects on the admin change list page Set ``ordering`` to specify how lists of objects should be ordered in the
should be ordered. This should be a list or tuple in the same format as a Django admin views. This should be a list or tuple in the same format as a
model's ``ordering`` parameter. model's ``ordering`` parameter.
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
@ -1089,8 +1089,36 @@ information.
``InlineModelAdmin`` options ``InlineModelAdmin`` options
----------------------------- -----------------------------
The ``InlineModelAdmin`` class is a subclass of ``ModelAdmin`` so it inherits ``InlineModelAdmin`` shares many of the same features as ``ModelAdmin``, and
all the same functionality as well as some of its own: adds some of its own (the shared features are actually defined in the
``BaseModelAdmin`` superclass). The shared features are:
- :attr:`~InlineModelAdmin.form`
- :attr:`~ModelAdmin.fieldsets`
- :attr:`~ModelAdmin.fields`
- :attr:`~ModelAdmin.exclude`
- :attr:`~ModelAdmin.filter_horizontal`
- :attr:`~ModelAdmin.filter_vertical`
- :attr:`~ModelAdmin.prepopulated_fields`
- :attr:`~ModelAdmin.radio_fields`
- :attr:`~InlineModelAdmin.raw_id_fields`
.. versionadded:: 1.1
- :meth:`~ModelAdmin.formfield_for_foreignkey`
- :meth:`~ModelAdmin.formfield_for_manytomany`
.. versionadded:: 1.2
- :attr:`~ModelAdmin.readonly_fields`
- :attr:`~ModelAdmin.formfield_overrides`
.. versionadded:: 1.3
- :attr:`~ModelAdmin.ordering`
- :meth:`~ModelAdmin.queryset`
The ``InlineModelAdmin`` class adds:
.. attribute:: InlineModelAdmin.model .. attribute:: InlineModelAdmin.model
@ -1118,7 +1146,6 @@ all the same functionality as well as some of its own:
.. attribute:: InlineModelAdmin.extra .. attribute:: InlineModelAdmin.extra
This controls the number of extra forms the formset will display in This controls the number of extra forms the formset will display in
addition to the initial forms. See the addition to the initial forms. See the
:doc:`formsets documentation </topics/forms/formsets>` for more :doc:`formsets documentation </topics/forms/formsets>` for more

View File

@ -1,5 +1,6 @@
# coding: utf-8 # coding: utf-8
from django.db import models from django.db import models
from django.contrib import admin
class Band(models.Model): class Band(models.Model):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
@ -8,3 +9,18 @@ class Band(models.Model):
class Meta: class Meta:
ordering = ('name',) ordering = ('name',)
class Song(models.Model):
band = models.ForeignKey(Band)
name = models.CharField(max_length=100)
duration = models.IntegerField()
class Meta:
ordering = ('name',)
class SongInlineDefaultOrdering(admin.StackedInline):
model = Song
class SongInlineNewOrdering(admin.StackedInline):
model = Song
ordering = ('duration', )

View File

@ -1,7 +1,7 @@
from django.test import TestCase from django.test import TestCase
from django.contrib.admin.options import ModelAdmin from django.contrib.admin.options import ModelAdmin
from models import Band from models import Band, Song, SongInlineDefaultOrdering, SongInlineNewOrdering
class TestAdminOrdering(TestCase): class TestAdminOrdering(TestCase):
""" """
@ -37,3 +37,37 @@ class TestAdminOrdering(TestCase):
ma = BandAdmin(Band, None) ma = BandAdmin(Band, None)
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)
class TestInlineModelAdminOrdering(TestCase):
"""
Let's make sure that InlineModelAdmin.queryset uses the ordering we define
in InlineModelAdmin.
"""
def setUp(self):
b = Band(name='Aerosmith', bio='', rank=3)
b.save()
self.b = b
s1 = Song(band=b, name='Pink', duration=235)
s1.save()
s2 = Song(band=b, name='Dude (Looks Like a Lady)', duration=264)
s2.save()
s3 = Song(band=b, name='Jaded', duration=214)
s3.save()
def test_default_ordering(self):
"""
The default ordering should be by name, as specified in the inner Meta
class.
"""
inline = SongInlineDefaultOrdering(self.b, None)
names = [s.name for s in inline.queryset(None)]
self.assertEqual([u'Dude (Looks Like a Lady)', u'Jaded', u'Pink'], names)
def test_specified_ordering(self):
"""
Let's check with ordering set to something different than the default.
"""
inline = SongInlineNewOrdering(self.b, None)
names = [s.name for s in inline.queryset(None)]
self.assertEqual([u'Jaded', u'Pink', u'Dude (Looks Like a Lady)'], names)