Introduced ModelAdmin.get_fields() and refactored get_fieldsets() to use it.

Refs #18681.

This also starts the deprecation of ModelAdmin.declared_fieldsets
This commit is contained in:
Loic Bistuer 2013-07-31 12:52:11 +07:00 committed by Tim Graham
parent 61ecb5f48a
commit ebb3e50243
5 changed files with 80 additions and 13 deletions

View File

@ -2,6 +2,7 @@ from collections import OrderedDict
import copy import copy
import operator import operator
from functools import partial, reduce, update_wrapper from functools import partial, reduce, update_wrapper
import warnings
from django import forms from django import forms
from django.conf import settings from django.conf import settings
@ -238,13 +239,49 @@ class BaseModelAdmin(six.with_metaclass(RenameBaseModelAdminMethods)):
return db_field.formfield(**kwargs) return db_field.formfield(**kwargs)
def _declared_fieldsets(self): @property
def declared_fieldsets(self):
warnings.warn(
"ModelAdmin.declared_fieldsets is deprecated and "
"will be removed in Django 1.9.",
PendingDeprecationWarning, stacklevel=2
)
if self.fieldsets: if self.fieldsets:
return self.fieldsets return self.fieldsets
elif self.fields: elif self.fields:
return [(None, {'fields': self.fields})] return [(None, {'fields': self.fields})]
return None return None
declared_fieldsets = property(_declared_fieldsets)
def get_fields(self, request, obj=None):
"""
Hook for specifying fields.
"""
return self.fields
def get_fieldsets(self, request, obj=None):
"""
Hook for specifying fieldsets.
"""
# We access the property and check if it triggers a warning.
# If it does, then it's ours and we can safely ignore it, but if
# it doesn't then it has been overriden so we must warn about the
# deprecation.
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
declared_fieldsets = self.declared_fieldsets
if len(w) != 1 or not issubclass(w[0].category, PendingDeprecationWarning):
warnings.warn(
"ModelAdmin.declared_fieldsets is deprecated and "
"will be removed in Django 1.9.",
PendingDeprecationWarning
)
if declared_fieldsets:
return declared_fieldsets
if self.fieldsets:
return self.fieldsets
return [(None, {'fields': self.get_fields(request, obj)})]
def get_ordering(self, request): def get_ordering(self, request):
""" """
@ -478,13 +515,11 @@ class ModelAdmin(BaseModelAdmin):
'delete': self.has_delete_permission(request), 'delete': self.has_delete_permission(request),
} }
def get_fieldsets(self, request, obj=None): def get_fields(self, request, obj=None):
"Hook for specifying fieldsets for the add form." if self.fields:
if self.declared_fieldsets: return self.fields
return self.declared_fieldsets
form = self.get_form(request, obj, fields=None) form = self.get_form(request, obj, fields=None)
fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return list(form.base_fields) + list(self.get_readonly_fields(request, obj))
return [(None, {'fields': fields})]
def get_form(self, request, obj=None, **kwargs): def get_form(self, request, obj=None, **kwargs):
""" """
@ -1657,12 +1692,11 @@ class InlineModelAdmin(BaseModelAdmin):
return inlineformset_factory(self.parent_model, self.model, **defaults) return inlineformset_factory(self.parent_model, self.model, **defaults)
def get_fieldsets(self, request, obj=None): def get_fields(self, request, obj=None):
if self.declared_fieldsets: if self.fields:
return self.declared_fieldsets return self.fields
form = self.get_formset(request, obj, fields=None).form form = self.get_formset(request, obj, fields=None).form
fields = list(form.base_fields) + list(self.get_readonly_fields(request, obj)) return list(form.base_fields) + list(self.get_readonly_fields(request, obj))
return [(None, {'fields': fields})]
def get_queryset(self, request): def get_queryset(self, request):
queryset = super(InlineModelAdmin, self).get_queryset(request) queryset = super(InlineModelAdmin, self).get_queryset(request)

View File

@ -426,6 +426,8 @@ these changes.
* ``django.utils.datastructures.SortedDict`` will be removed. Use * ``django.utils.datastructures.SortedDict`` will be removed. Use
:class:`collections.OrderedDict` from the Python standard library instead. :class:`collections.OrderedDict` from the Python standard library instead.
* ``ModelAdmin.declared_fieldsets`` will be removed.
2.0 2.0
--- ---

View File

@ -1218,6 +1218,14 @@ templates used by the :class:`ModelAdmin` views:
changelist that will be linked to the change view, as described in the changelist that will be linked to the change view, as described in the
:attr:`ModelAdmin.list_display_links` section. :attr:`ModelAdmin.list_display_links` section.
.. method:: ModelAdmin.get_fields(self, request, obj=None)
.. versionadded:: 1.7
The ``get_fields`` method is given the ``HttpRequest`` and the ``obj``
being edited (or ``None`` on an add form) and is expected to return a list
of fields, as described above in the :attr:`ModelAdmin.fields` section.
.. method:: ModelAdmin.get_fieldsets(self, request, obj=None) .. method:: ModelAdmin.get_fieldsets(self, request, obj=None)
The ``get_fieldsets`` method is given the ``HttpRequest`` and the ``obj`` The ``get_fieldsets`` method is given the ``HttpRequest`` and the ``obj``

View File

@ -113,6 +113,11 @@ Minor features
* The admin's search fields can now be customized per-request thanks to the new * The admin's search fields can now be customized per-request thanks to the new
:meth:`django.contrib.admin.ModelAdmin.get_search_fields` method. :meth:`django.contrib.admin.ModelAdmin.get_search_fields` method.
* The :meth:`ModelAdmin.get_fields()
<django.contrib.admin.ModelAdmin.get_fields>` method may be overridden to
customize the value of :attr:`ModelAdmin.fields
<django.contrib.admin.ModelAdmin.fields>`.
Backwards incompatible changes in 1.7 Backwards incompatible changes in 1.7
===================================== =====================================
@ -182,3 +187,11 @@ than simply ``myapp/models.py``, Django would look for :ref:`initial SQL data
<initial-sql>` in ``myapp/models/sql/``. This bug has been fixed so that Django <initial-sql>` in ``myapp/models/sql/``. This bug has been fixed so that Django
will search ``myapp/sql/`` as documented. The old location will continue to will search ``myapp/sql/`` as documented. The old location will continue to
work until Django 1.9. work until Django 1.9.
``declared_fieldsets`` attribute on ``ModelAdmin.``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``ModelAdmin.declared_fieldsets`` was deprecated. Despite being a private API,
it will go through a regular deprecation path. This attribute was mostly used
by methods that bypassed ``ModelAdmin.get_fieldsets()`` but this was considered
a bug and has been addressed.

View File

@ -51,6 +51,12 @@ class ModelAdminTests(TestCase):
self.assertEqual(list(ma.get_form(request).base_fields), self.assertEqual(list(ma.get_form(request).base_fields),
['name', 'bio', 'sign_date']) ['name', 'bio', 'sign_date'])
self.assertEqual(list(ma.get_fields(request)),
['name', 'bio', 'sign_date'])
self.assertEqual(list(ma.get_fields(request, self.band)),
['name', 'bio', 'sign_date'])
def test_default_fieldsets(self): def test_default_fieldsets(self):
# fieldsets_add and fieldsets_change should return a special data structure that # fieldsets_add and fieldsets_change should return a special data structure that
# is used in the templates. They should generate the "right thing" whether we # is used in the templates. They should generate the "right thing" whether we
@ -97,6 +103,10 @@ class ModelAdminTests(TestCase):
ma = BandAdmin(Band, self.site) ma = BandAdmin(Band, self.site)
self.assertEqual(list(ma.get_fields(request)), ['name'])
self.assertEqual(list(ma.get_fields(request, self.band)), ['name'])
self.assertEqual(ma.get_fieldsets(request), self.assertEqual(ma.get_fieldsets(request),
[(None, {'fields': ['name']})]) [(None, {'fields': ['name']})])