Commit 61524b09 authored by Tim Graham's avatar Tim Graham
Browse files

Fixed #18388 - Added InlineModelAdmin.get_max_num hook.

Thanks d.willy.c.c@ for the suggestion and Melevir and Areski Belaid for work
on the patch.
parent 07a73a27
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -1516,6 +1516,10 @@ class InlineModelAdmin(BaseModelAdmin):
        """Hook for customizing the number of extra inline forms."""
        return self.extra

    def get_max_num(self, request, obj=None, **kwargs):
        """Hook for customizing the max number of extra inline forms."""
        return self.max_num

    def get_formset(self, request, obj=None, **kwargs):
        """Returns a BaseInlineFormSet class for use in admin add/change views."""
        if 'fields' in kwargs:
@@ -1543,7 +1547,7 @@ class InlineModelAdmin(BaseModelAdmin):
            "exclude": exclude,
            "formfield_callback": partial(self.formfield_for_dbfield, request=request),
            "extra": self.get_extra(request, obj, **kwargs),
            "max_num": self.max_num,
            "max_num": self.get_max_num(request, obj, **kwargs),
            "can_delete": can_delete,
        }

+26 −0
Original line number Diff line number Diff line
@@ -1728,6 +1728,11 @@ The ``InlineModelAdmin`` class adds:
    doesn't directly correlate to the number of objects, but can if the value
    is small enough. See :ref:`model-formsets-max-num` for more information.

    .. versionadded:: 1.6

    :meth:`InlineModelAdmin.get_max_num` also allows you to customize the
    maximum number of extra forms.

.. attribute:: InlineModelAdmin.raw_id_fields

    By default, Django's admin uses a select-box interface (<select>) for
@@ -1787,6 +1792,27 @@ The ``InlineModelAdmin`` class adds:
                    return extra - obj.binarytree_set.count()
                return extra

.. method:: InlineModelAdmin.get_max_num(self, request, obj=None, **kwargs)

    .. versionadded:: 1.6

    Returns the maximum number of extra inline forms to use. By default,
    returns the :attr:`InlineModelAdmin.max_num` attribute.

    Override this method to programmatically determine the maximum number of
    inline forms. For example, this may be based on the model instance
    (passed as the keyword argument ``obj``)::

        class BinaryTreeAdmin(admin.TabularInline):
            model = BinaryTree

            def get_max_num(self, request, obj=None, **kwargs):
                max_num = 10
                if obj.parent:
                    return max_num - 5
                return max_num


Working with a model with two or more foreign keys to the same parent model
---------------------------------------------------------------------------

+3 −2
Original line number Diff line number Diff line
@@ -292,9 +292,10 @@ Minor features
  :meth:`~django.db.models.query.QuerySet.select_related` can be cleared using
  ``select_related(None)``.

* The :meth:`~django.contrib.admin.InlineModelAdmin.get_extra` method on
* The :meth:`~django.contrib.admin.InlineModelAdmin.get_extra` and
  :meth:`~django.contrib.admin.InlineModelAdmin.get_max_num` methods on
  :class:`~django.contrib.admin.InlineModelAdmin` may be overridden to
  customize the number of extra inline forms.
  customize the extra and maximum number of inline forms.

Backwards incompatible changes in 1.6
=====================================
+7 −2
Original line number Diff line number Diff line
@@ -129,7 +129,7 @@ class ChildModel1Inline(admin.TabularInline):
class ChildModel2Inline(admin.StackedInline):
    model = ChildModel2

# admin for #19425
# admin for #19425 and #18388
class BinaryTreeAdmin(admin.TabularInline):
    model = BinaryTree

@@ -137,9 +137,14 @@ class BinaryTreeAdmin(admin.TabularInline):
        extra = 2
        if obj:
            return extra - obj.binarytree_set.count()

        return extra

    def get_max_num(self, request, obj=None, **kwargs):
        max_num = 3
        if obj:
            return max_num - obj.binarytree_set.count()
        return max_num

# admin for #19524
class SightingInline(admin.TabularInline):
    model = Sighting
+6 −0
Original line number Diff line number Diff line
@@ -197,12 +197,18 @@ class TestInline(TestCase):
        bt_head = BinaryTree.objects.create(name="Tree Head")
        bt_child = BinaryTree.objects.create(name="First Child", parent=bt_head)

        # The maximum number of forms should respect 'get_max_num' on the
        # ModelAdmin
        max_forms_input = '<input id="id_binarytree_set-MAX_NUM_FORMS" name="binarytree_set-MAX_NUM_FORMS" type="hidden" value="%d" />'
        # The total number of forms will remain the same in either case
        total_forms_hidden = '<input id="id_binarytree_set-TOTAL_FORMS" name="binarytree_set-TOTAL_FORMS" type="hidden" value="2" />'

        response = self.client.get('/admin/admin_inlines/binarytree/add/')
        self.assertContains(response, max_forms_input % 3)
        self.assertContains(response, total_forms_hidden)

        response = self.client.get("/admin/admin_inlines/binarytree/%d/" % bt_head.id)
        self.assertContains(response, max_forms_input % 2)
        self.assertContains(response, total_forms_hidden)