Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Fixed #20702 -- Deprecated get_formsets in favor of get_formsets_with_inlines #1634

Closed
wants to merge 1 commit into from

2 participants

@timgraham
Owner

No description provided.

@tim-schilling tim-schilling Fixed #20702 -- Deprecated get_formsets in favor of get_formsets_with…
…_inlines.

Thanks stanislas.guerra at gmail.com for the report.
2e94e55
@timgraham
Owner

merged in 0d1ba84

@timgraham timgraham closed this
@timgraham timgraham deleted the timgraham:20702a branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 16, 2013
  1. @tim-schilling @timgraham

    Fixed #20702 -- Deprecated get_formsets in favor of get_formsets_with…

    tim-schilling authored timgraham committed
    …_inlines.
    
    Thanks stanislas.guerra at gmail.com for the report.
This page is out of date. Refresh to see the latest.
View
59 django/contrib/admin/options.py
@@ -602,10 +602,48 @@ def get_changelist_formset(self, request, **kwargs):
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)
@@ -1185,8 +1223,6 @@ def add_view(self, request, form_url='', extra_context=None):
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():
@@ -1195,7 +1231,7 @@ def add_view(self, request, form_url='', extra_context=None):
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)
@@ -1213,7 +1249,7 @@ def add_view(self, request, form_url='', extra_context=None):
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),
@@ -1266,7 +1302,6 @@ def change_view(self, request, object_id, form_url='', extra_context=None):
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():
@@ -1275,7 +1310,7 @@ def change_view(self, request, object_id, form_url='', extra_context=None):
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)
@@ -1285,7 +1320,7 @@ def change_view(self, request, object_id, form_url='', extra_context=None):
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),
@@ -1566,14 +1601,15 @@ def history_view(self, request, object_id, extra_context=None):
"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:
@@ -1590,7 +1626,8 @@ def _create_formsets(self, request, obj, inline_instances):
'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):
View
2  docs/internals/deprecation.txt
@@ -444,6 +444,8 @@ these changes.
* ``ModelAdmin.declared_fieldsets`` will be removed.
+* ``ModelAdmin.get_formsets`` will be removed.
+
2.0
---
View
25 docs/ref/contrib/admin/index.txt
@@ -426,7 +426,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
@@ -1337,7 +1337,10 @@ templates used by the :class:`ModelAdmin` views:
.. method:: ModelAdmin.get_formsets(self, request, obj=None)
- Yields :class:`InlineModelAdmin`\s for use in admin add and change views.
+ .. 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
view, you could override ``get_formsets`` as follows::
@@ -1352,6 +1355,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
View
20 docs/releases/1.7.txt
@@ -446,13 +446,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``
~~~~~~~~~~
@@ -460,3 +460,11 @@ a bug and has been addressed.
The ``syncdb`` command has been deprecated in favour of the new ``migrate``
command. ``migrate`` takes the same arguments as ``syncdb`` used to plus a few
more, so it's safe to just change the name you're calling and nothing else.
+
+``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
+handle the case of limiting the inlines of a ``ModelAdmin`` when fetching the
+formsets of the inlines.
View
93 tests/generic_inline_admin/tests.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
+import warnings
from django.conf import settings
from django.contrib import admin
@@ -277,7 +278,7 @@ class EpisodeAdmin(admin.ModelAdmin):
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):
@@ -307,7 +308,7 @@ class EpisodeAdmin(admin.ModelAdmin):
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` -----------------
@@ -323,7 +324,7 @@ class EpisodeAdmin(admin.ModelAdmin):
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):
@@ -345,3 +346,89 @@ def get_fieldsets(self, request, obj=None):
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__)
View
8 tests/modeladmin/tests.py
@@ -207,7 +207,7 @@ class BandAdmin(ModelAdmin):
ma = BandAdmin(Band, 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),
['main_band', 'opening_band', 'id', 'DELETE'])
def test_custom_form_meta_exclude(self):
@@ -253,7 +253,7 @@ class BandAdmin(ModelAdmin):
ma = BandAdmin(Band, 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),
['main_band', 'opening_band', 'day', 'id', 'DELETE'])
def test_custom_form_validation(self):
@@ -327,7 +327,7 @@ class BandAdmin(ModelAdmin):
ma = BandAdmin(Band, 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),
['main_band', 'day', 'transport', 'id', 'DELETE'])
def test_queryset_override(self):
@@ -521,7 +521,7 @@ class BandAdmin(ModelAdmin):
ma = BandAdmin(Band, 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),
['extra', 'transport', 'id', 'DELETE', 'main_band'])
Something went wrong with that request. Please try again.