Loading django/contrib/admin/options.py +48 −11 Original line number Diff line number Diff line Loading @@ -602,10 +602,48 @@ class ModelAdmin(BaseModelAdmin): self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults) def get_formsets(self, request, obj=None): def _get_formsets(self, request, obj): """ Helper function that exists to allow the deprecation warning to be executed while this function continues to return a generator. """ for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj) def get_formsets(self, request, obj=None): warnings.warn( "ModelAdmin.get_formsets() is deprecated and will be removed in " "Django 1.9. Use ModelAdmin.get_formsets_with_inlines() instead.", PendingDeprecationWarning, stacklevel=2 ) return self._get_formsets(request, obj) def get_formsets_with_inlines(self, request, obj=None): """ Yields formsets and the corresponding inlines. """ # We call get_formsets() [deprecated] 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 overridden so we must warn about the # deprecation. with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") formsets = self.get_formsets(request, obj) if len(w) != 1 or not issubclass(w[0].category, PendingDeprecationWarning): warnings.warn( "ModelAdmin.get_formsets() is deprecated and will be removed in " "Django 1.9. Use ModelAdmin.get_formsets_with_inlines() instead.", PendingDeprecationWarning ) if formsets: zipped = zip(formsets, self.get_inline_instances(request, None)) for formset, inline in zipped: yield formset, inline else: for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj), inline def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page) Loading Loading @@ -1185,8 +1223,6 @@ class ModelAdmin(BaseModelAdmin): raise PermissionDenied ModelForm = self.get_form(request) formsets = [] inline_instances = self.get_inline_instances(request, None) if request.method == 'POST': form = ModelForm(request.POST, request.FILES) if form.is_valid(): Loading @@ -1195,7 +1231,7 @@ class ModelAdmin(BaseModelAdmin): else: form_validated = False new_object = self.model() formsets = self._create_formsets(request, new_object, inline_instances) formsets, inline_instances = self._create_formsets(request, new_object) if all_valid(formsets) and form_validated: self.save_model(request, new_object, form, False) self.save_related(request, form, formsets, False) Loading @@ -1213,7 +1249,7 @@ class ModelAdmin(BaseModelAdmin): if isinstance(f, models.ManyToManyField): initial[k] = initial[k].split(",") form = ModelForm(initial=initial) formsets = self._create_formsets(request, self.model(), inline_instances) formsets, inline_instances = self._create_formsets(request, self.model()) adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)), self.get_prepopulated_fields(request), Loading Loading @@ -1266,7 +1302,6 @@ class ModelAdmin(BaseModelAdmin): current_app=self.admin_site.name)) ModelForm = self.get_form(request, obj) inline_instances = self.get_inline_instances(request, obj) if request.method == 'POST': form = ModelForm(request.POST, request.FILES, instance=obj) if form.is_valid(): Loading @@ -1275,7 +1310,7 @@ class ModelAdmin(BaseModelAdmin): else: form_validated = False new_object = obj formsets = self._create_formsets(request, new_object, inline_instances) formsets, inline_instances = self._create_formsets(request, new_object) if all_valid(formsets) and form_validated: self.save_model(request, new_object, form, True) self.save_related(request, form, formsets, True) Loading @@ -1285,7 +1320,7 @@ class ModelAdmin(BaseModelAdmin): else: form = ModelForm(instance=obj) formsets = self._create_formsets(request, obj, inline_instances) formsets, inline_instances = self._create_formsets(request, obj) adminForm = helpers.AdminForm(form, self.get_fieldsets(request, obj), self.get_prepopulated_fields(request, obj), Loading Loading @@ -1566,14 +1601,15 @@ class ModelAdmin(BaseModelAdmin): "admin/object_history.html" ], context, current_app=self.admin_site.name) def _create_formsets(self, request, obj, inline_instances): def _create_formsets(self, request, obj): "Helper function to generate formsets for add/change_view." formsets = [] inline_instances = [] prefixes = {} get_formsets_args = [request] if obj.pk: get_formsets_args.append(obj) for FormSet, inline in zip(self.get_formsets(*get_formsets_args), inline_instances): for FormSet, inline in self.get_formsets_with_inlines(*get_formsets_args): prefix = FormSet.get_default_prefix() prefixes[prefix] = prefixes.get(prefix, 0) + 1 if prefixes[prefix] != 1 or not prefix: Loading @@ -1590,7 +1626,8 @@ class ModelAdmin(BaseModelAdmin): 'save_as_new': '_saveasnew' in request.POST }) formsets.append(FormSet(**formset_params)) return formsets inline_instances.append(inline) return formsets, inline_instances class InlineModelAdmin(BaseModelAdmin): Loading docs/internals/deprecation.txt +2 −0 Original line number Diff line number Diff line Loading @@ -453,6 +453,8 @@ these changes. * ``django.db.backends.util`` * ``django.forms.util`` * ``ModelAdmin.get_formsets`` will be removed. 2.0 --- Loading docs/ref/contrib/admin/index.txt +23 −2 Original line number Diff line number Diff line Loading @@ -454,7 +454,7 @@ subclass:: .. attribute:: ModelAdmin.inlines See :class:`InlineModelAdmin` objects below as well as :meth:`ModelAdmin.get_formsets`. :meth:`ModelAdmin.get_formsets_with_inlines`. .. attribute:: ModelAdmin.list_display Loading Loading @@ -1365,6 +1365,9 @@ templates used by the :class:`ModelAdmin` views: .. method:: ModelAdmin.get_formsets(self, request, obj=None) .. deprecated:: 1.7 Use :meth:`get_formsets_with_inlines()` instead. Yields :class:`InlineModelAdmin`\s for use in admin add and change views. For example if you wanted to display a particular inline only in the change Loading @@ -1380,6 +1383,24 @@ templates used by the :class:`ModelAdmin` views: continue yield inline.get_formset(request, obj) .. method:: ModelAdmin.get_formsets_with_inlines(self, request, obj=None) Yields (``FormSet``, :class:`InlineModelAdmin`) pairs for use in admin add and change views. For example if you wanted to display a particular inline only in the change view, you could override ``get_formsets_with_inlines`` as follows:: class MyModelAdmin(admin.ModelAdmin): inlines = [MyInline, SomeOtherInline] def get_formsets_with_inlines(self, request, obj=None): for inline in self.get_inline_instances(request, obj): # hide MyInline in the add view if isinstance(inline, MyInline) and obj is None: continue yield inline.get_formset(request, obj), inline .. method:: ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs) The ``formfield_for_foreignkey`` method on a ``ModelAdmin`` allows you to Loading docs/releases/1.7.txt +13 −6 Original line number Diff line number Diff line Loading @@ -466,13 +466,13 @@ than simply ``myapp/models.py``, Django would look for :ref:`initial SQL data will search ``myapp/sql/`` as documented. The old location will continue to work until Django 1.9. ``declared_fieldsets`` attribute on ``ModelAdmin.`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``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. ``ModelAdmin.declared_fieldsets`` has been 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. ``syncdb`` ~~~~~~~~~~ Loading @@ -491,3 +491,10 @@ to ``utils.py`` in an effort to unify all util and utils references: * ``django.contrib.gis.db.backends.util`` * ``django.db.backends.util`` * ``django.forms.util`` ``get_formsets`` method on ``ModelAdmin`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``ModelAdmin.get_formsets`` has been deprecated in favor of the new :meth:`~django.contrib.admin.ModelAdmin.get_formsets_with_inlines`, in order to better handle the case of selecting showing inlines on a ``ModelAdmin``. tests/generic_inline_admin/tests.py +90 −3 Original line number Diff line number Diff line # -*- coding: utf-8 -*- from __future__ import unicode_literals import warnings from django.conf import settings from django.contrib import admin Loading Loading @@ -277,7 +278,7 @@ class GenericInlineModelAdminTest(TestCase): ma = EpisodeAdmin(Episode, self.site) self.assertEqual( list(list(ma.get_formsets(request))[0]().forms[0].fields), list(list(ma.get_formsets_with_inlines(request))[0][0]().forms[0].fields), ['keywords', 'id', 'DELETE']) def test_custom_form_meta_exclude(self): Loading Loading @@ -307,7 +308,7 @@ class GenericInlineModelAdminTest(TestCase): ma = EpisodeAdmin(Episode, self.site) self.assertEqual( list(list(ma.get_formsets(request))[0]().forms[0].fields), list(list(ma.get_formsets_with_inlines(request))[0][0]().forms[0].fields), ['url', 'keywords', 'id', 'DELETE']) # Then, only with `ModelForm` ----------------- Loading @@ -323,7 +324,7 @@ class GenericInlineModelAdminTest(TestCase): ma = EpisodeAdmin(Episode, self.site) self.assertEqual( list(list(ma.get_formsets(request))[0]().forms[0].fields), list(list(ma.get_formsets_with_inlines(request))[0][0]().forms[0].fields), ['description', 'keywords', 'id', 'DELETE']) def test_get_fieldsets(self): Loading @@ -345,3 +346,89 @@ class GenericInlineModelAdminTest(TestCase): ma = MediaInline(Media, self.site) form = ma.get_formset(None).form self.assertEqual(form._meta.fields, ['url', 'description']) def test_get_formsets_with_inlines(self): """ get_formsets() triggers a deprecation warning when get_formsets is overridden. """ class MediaForm(ModelForm): class Meta: model = Media exclude = ['url'] class MediaInline(GenericTabularInline): exclude = ['description'] form = MediaForm model = Media class EpisodeAdmin(admin.ModelAdmin): inlines = [ MediaInline ] def get_formsets(self, request, obj=None): return [] with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") ma = EpisodeAdmin(Episode, self.site) list(ma.get_formsets_with_inlines(request)) # Verify that the deprecation warning was triggered when get_formsets was called # This verifies that we called that method. self.assertEqual(len(w), 1) self.assertTrue(issubclass(w[0].category, PendingDeprecationWarning)) class EpisodeAdmin(admin.ModelAdmin): inlines = [ MediaInline ] with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") ma = EpisodeAdmin(Episode, self.site) list(ma.get_formsets_with_inlines(request)) self.assertEqual(len(w), 0) def test_get_formsets_with_inlines_returns_tuples(self): """ Ensure that get_formsets_with_inlines() returns the correct tuples. """ class MediaForm(ModelForm): class Meta: model = Media exclude = ['url'] class MediaInline(GenericTabularInline): form = MediaForm model = Media class AlternateInline(GenericTabularInline): form = MediaForm model = Media class EpisodeAdmin(admin.ModelAdmin): inlines = [ AlternateInline, MediaInline ] ma = EpisodeAdmin(Episode, self.site) inlines = ma.get_inline_instances(request) for (formset, inline), other_inline in zip(ma.get_formsets_with_inlines(request), inlines): self.assertIsInstance(formset, other_inline.get_formset(request).__class__) class EpisodeAdmin(admin.ModelAdmin): inlines = [ AlternateInline, MediaInline ] def get_formsets(self, request, obj=None): # Catch the deprecation warning to force the usage of get_formsets with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") return super(EpisodeAdmin, self).get_formsets(request, obj) ma = EpisodeAdmin(Episode, self.site) inlines = ma.get_inline_instances(request) with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") for (formset, inline), other_inline in zip(ma.get_formsets_with_inlines(request), inlines): self.assertIsInstance(formset, other_inline.get_formset(request).__class__) Loading
django/contrib/admin/options.py +48 −11 Original line number Diff line number Diff line Loading @@ -602,10 +602,48 @@ class ModelAdmin(BaseModelAdmin): self.get_changelist_form(request), extra=0, fields=self.list_editable, **defaults) def get_formsets(self, request, obj=None): def _get_formsets(self, request, obj): """ Helper function that exists to allow the deprecation warning to be executed while this function continues to return a generator. """ for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj) def get_formsets(self, request, obj=None): warnings.warn( "ModelAdmin.get_formsets() is deprecated and will be removed in " "Django 1.9. Use ModelAdmin.get_formsets_with_inlines() instead.", PendingDeprecationWarning, stacklevel=2 ) return self._get_formsets(request, obj) def get_formsets_with_inlines(self, request, obj=None): """ Yields formsets and the corresponding inlines. """ # We call get_formsets() [deprecated] 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 overridden so we must warn about the # deprecation. with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") formsets = self.get_formsets(request, obj) if len(w) != 1 or not issubclass(w[0].category, PendingDeprecationWarning): warnings.warn( "ModelAdmin.get_formsets() is deprecated and will be removed in " "Django 1.9. Use ModelAdmin.get_formsets_with_inlines() instead.", PendingDeprecationWarning ) if formsets: zipped = zip(formsets, self.get_inline_instances(request, None)) for formset, inline in zipped: yield formset, inline else: for inline in self.get_inline_instances(request, obj): yield inline.get_formset(request, obj), inline def get_paginator(self, request, queryset, per_page, orphans=0, allow_empty_first_page=True): return self.paginator(queryset, per_page, orphans, allow_empty_first_page) Loading Loading @@ -1185,8 +1223,6 @@ class ModelAdmin(BaseModelAdmin): raise PermissionDenied ModelForm = self.get_form(request) formsets = [] inline_instances = self.get_inline_instances(request, None) if request.method == 'POST': form = ModelForm(request.POST, request.FILES) if form.is_valid(): Loading @@ -1195,7 +1231,7 @@ class ModelAdmin(BaseModelAdmin): else: form_validated = False new_object = self.model() formsets = self._create_formsets(request, new_object, inline_instances) formsets, inline_instances = self._create_formsets(request, new_object) if all_valid(formsets) and form_validated: self.save_model(request, new_object, form, False) self.save_related(request, form, formsets, False) Loading @@ -1213,7 +1249,7 @@ class ModelAdmin(BaseModelAdmin): if isinstance(f, models.ManyToManyField): initial[k] = initial[k].split(",") form = ModelForm(initial=initial) formsets = self._create_formsets(request, self.model(), inline_instances) formsets, inline_instances = self._create_formsets(request, self.model()) adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)), self.get_prepopulated_fields(request), Loading Loading @@ -1266,7 +1302,6 @@ class ModelAdmin(BaseModelAdmin): current_app=self.admin_site.name)) ModelForm = self.get_form(request, obj) inline_instances = self.get_inline_instances(request, obj) if request.method == 'POST': form = ModelForm(request.POST, request.FILES, instance=obj) if form.is_valid(): Loading @@ -1275,7 +1310,7 @@ class ModelAdmin(BaseModelAdmin): else: form_validated = False new_object = obj formsets = self._create_formsets(request, new_object, inline_instances) formsets, inline_instances = self._create_formsets(request, new_object) if all_valid(formsets) and form_validated: self.save_model(request, new_object, form, True) self.save_related(request, form, formsets, True) Loading @@ -1285,7 +1320,7 @@ class ModelAdmin(BaseModelAdmin): else: form = ModelForm(instance=obj) formsets = self._create_formsets(request, obj, inline_instances) formsets, inline_instances = self._create_formsets(request, obj) adminForm = helpers.AdminForm(form, self.get_fieldsets(request, obj), self.get_prepopulated_fields(request, obj), Loading Loading @@ -1566,14 +1601,15 @@ class ModelAdmin(BaseModelAdmin): "admin/object_history.html" ], context, current_app=self.admin_site.name) def _create_formsets(self, request, obj, inline_instances): def _create_formsets(self, request, obj): "Helper function to generate formsets for add/change_view." formsets = [] inline_instances = [] prefixes = {} get_formsets_args = [request] if obj.pk: get_formsets_args.append(obj) for FormSet, inline in zip(self.get_formsets(*get_formsets_args), inline_instances): for FormSet, inline in self.get_formsets_with_inlines(*get_formsets_args): prefix = FormSet.get_default_prefix() prefixes[prefix] = prefixes.get(prefix, 0) + 1 if prefixes[prefix] != 1 or not prefix: Loading @@ -1590,7 +1626,8 @@ class ModelAdmin(BaseModelAdmin): 'save_as_new': '_saveasnew' in request.POST }) formsets.append(FormSet(**formset_params)) return formsets inline_instances.append(inline) return formsets, inline_instances class InlineModelAdmin(BaseModelAdmin): Loading
docs/internals/deprecation.txt +2 −0 Original line number Diff line number Diff line Loading @@ -453,6 +453,8 @@ these changes. * ``django.db.backends.util`` * ``django.forms.util`` * ``ModelAdmin.get_formsets`` will be removed. 2.0 --- Loading
docs/ref/contrib/admin/index.txt +23 −2 Original line number Diff line number Diff line Loading @@ -454,7 +454,7 @@ subclass:: .. attribute:: ModelAdmin.inlines See :class:`InlineModelAdmin` objects below as well as :meth:`ModelAdmin.get_formsets`. :meth:`ModelAdmin.get_formsets_with_inlines`. .. attribute:: ModelAdmin.list_display Loading Loading @@ -1365,6 +1365,9 @@ templates used by the :class:`ModelAdmin` views: .. method:: ModelAdmin.get_formsets(self, request, obj=None) .. deprecated:: 1.7 Use :meth:`get_formsets_with_inlines()` instead. Yields :class:`InlineModelAdmin`\s for use in admin add and change views. For example if you wanted to display a particular inline only in the change Loading @@ -1380,6 +1383,24 @@ templates used by the :class:`ModelAdmin` views: continue yield inline.get_formset(request, obj) .. method:: ModelAdmin.get_formsets_with_inlines(self, request, obj=None) Yields (``FormSet``, :class:`InlineModelAdmin`) pairs for use in admin add and change views. For example if you wanted to display a particular inline only in the change view, you could override ``get_formsets_with_inlines`` as follows:: class MyModelAdmin(admin.ModelAdmin): inlines = [MyInline, SomeOtherInline] def get_formsets_with_inlines(self, request, obj=None): for inline in self.get_inline_instances(request, obj): # hide MyInline in the add view if isinstance(inline, MyInline) and obj is None: continue yield inline.get_formset(request, obj), inline .. method:: ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs) The ``formfield_for_foreignkey`` method on a ``ModelAdmin`` allows you to Loading
docs/releases/1.7.txt +13 −6 Original line number Diff line number Diff line Loading @@ -466,13 +466,13 @@ than simply ``myapp/models.py``, Django would look for :ref:`initial SQL data will search ``myapp/sql/`` as documented. The old location will continue to work until Django 1.9. ``declared_fieldsets`` attribute on ``ModelAdmin.`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``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. ``ModelAdmin.declared_fieldsets`` has been 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. ``syncdb`` ~~~~~~~~~~ Loading @@ -491,3 +491,10 @@ to ``utils.py`` in an effort to unify all util and utils references: * ``django.contrib.gis.db.backends.util`` * ``django.db.backends.util`` * ``django.forms.util`` ``get_formsets`` method on ``ModelAdmin`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``ModelAdmin.get_formsets`` has been deprecated in favor of the new :meth:`~django.contrib.admin.ModelAdmin.get_formsets_with_inlines`, in order to better handle the case of selecting showing inlines on a ``ModelAdmin``.
tests/generic_inline_admin/tests.py +90 −3 Original line number Diff line number Diff line # -*- coding: utf-8 -*- from __future__ import unicode_literals import warnings from django.conf import settings from django.contrib import admin Loading Loading @@ -277,7 +278,7 @@ class GenericInlineModelAdminTest(TestCase): ma = EpisodeAdmin(Episode, self.site) self.assertEqual( list(list(ma.get_formsets(request))[0]().forms[0].fields), list(list(ma.get_formsets_with_inlines(request))[0][0]().forms[0].fields), ['keywords', 'id', 'DELETE']) def test_custom_form_meta_exclude(self): Loading Loading @@ -307,7 +308,7 @@ class GenericInlineModelAdminTest(TestCase): ma = EpisodeAdmin(Episode, self.site) self.assertEqual( list(list(ma.get_formsets(request))[0]().forms[0].fields), list(list(ma.get_formsets_with_inlines(request))[0][0]().forms[0].fields), ['url', 'keywords', 'id', 'DELETE']) # Then, only with `ModelForm` ----------------- Loading @@ -323,7 +324,7 @@ class GenericInlineModelAdminTest(TestCase): ma = EpisodeAdmin(Episode, self.site) self.assertEqual( list(list(ma.get_formsets(request))[0]().forms[0].fields), list(list(ma.get_formsets_with_inlines(request))[0][0]().forms[0].fields), ['description', 'keywords', 'id', 'DELETE']) def test_get_fieldsets(self): Loading @@ -345,3 +346,89 @@ class GenericInlineModelAdminTest(TestCase): ma = MediaInline(Media, self.site) form = ma.get_formset(None).form self.assertEqual(form._meta.fields, ['url', 'description']) def test_get_formsets_with_inlines(self): """ get_formsets() triggers a deprecation warning when get_formsets is overridden. """ class MediaForm(ModelForm): class Meta: model = Media exclude = ['url'] class MediaInline(GenericTabularInline): exclude = ['description'] form = MediaForm model = Media class EpisodeAdmin(admin.ModelAdmin): inlines = [ MediaInline ] def get_formsets(self, request, obj=None): return [] with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") ma = EpisodeAdmin(Episode, self.site) list(ma.get_formsets_with_inlines(request)) # Verify that the deprecation warning was triggered when get_formsets was called # This verifies that we called that method. self.assertEqual(len(w), 1) self.assertTrue(issubclass(w[0].category, PendingDeprecationWarning)) class EpisodeAdmin(admin.ModelAdmin): inlines = [ MediaInline ] with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") ma = EpisodeAdmin(Episode, self.site) list(ma.get_formsets_with_inlines(request)) self.assertEqual(len(w), 0) def test_get_formsets_with_inlines_returns_tuples(self): """ Ensure that get_formsets_with_inlines() returns the correct tuples. """ class MediaForm(ModelForm): class Meta: model = Media exclude = ['url'] class MediaInline(GenericTabularInline): form = MediaForm model = Media class AlternateInline(GenericTabularInline): form = MediaForm model = Media class EpisodeAdmin(admin.ModelAdmin): inlines = [ AlternateInline, MediaInline ] ma = EpisodeAdmin(Episode, self.site) inlines = ma.get_inline_instances(request) for (formset, inline), other_inline in zip(ma.get_formsets_with_inlines(request), inlines): self.assertIsInstance(formset, other_inline.get_formset(request).__class__) class EpisodeAdmin(admin.ModelAdmin): inlines = [ AlternateInline, MediaInline ] def get_formsets(self, request, obj=None): # Catch the deprecation warning to force the usage of get_formsets with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") return super(EpisodeAdmin, self).get_formsets(request, obj) ma = EpisodeAdmin(Episode, self.site) inlines = ma.get_inline_instances(request) with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") for (formset, inline), other_inline in zip(ma.get_formsets_with_inlines(request), inlines): self.assertIsInstance(formset, other_inline.get_formset(request).__class__)