Bläddra i källkod

Refs #20347 -- Allowed customizing the maximum number of instantiated forms in generic_inlineformset_factory().

Follow up to 433dd737f94b09043f64b873b0ac067b3f97364b.
Mariusz Felisiak 4 år sedan
förälder
incheckning
3254991762

+ 3 - 1
django/contrib/contenttypes/forms.py

@@ -56,7 +56,8 @@ def generic_inlineformset_factory(model, form=ModelForm,
                                   extra=3, can_order=False, can_delete=True,
                                   max_num=None, formfield_callback=None,
                                   validate_max=False, for_concrete_model=True,
-                                  min_num=None, validate_min=False):
+                                  min_num=None, validate_min=False,
+                                  absolute_max=None):
     """
     Return a ``GenericInlineFormSet`` for the given kwargs.
 
@@ -75,6 +76,7 @@ def generic_inlineformset_factory(model, form=ModelForm,
         formset=formset, extra=extra, can_delete=can_delete,
         can_order=can_order, fields=fields, exclude=exclude, max_num=max_num,
         validate_max=validate_max, min_num=min_num, validate_min=validate_min,
+        absolute_max=absolute_max,
     )
     FormSet.ct_field = ct_field
     FormSet.ct_fk_field = fk_field

+ 5 - 1
docs/ref/contrib/contenttypes.txt

@@ -466,7 +466,7 @@ The :mod:`django.contrib.contenttypes.forms` module provides:
 
 .. class:: BaseGenericInlineFormSet
 
-.. function:: generic_inlineformset_factory(model, form=ModelForm, formset=BaseGenericInlineFormSet, ct_field="content_type", fk_field="object_id", fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, validate_max=False, for_concrete_model=True, min_num=None, validate_min=False)
+.. function:: generic_inlineformset_factory(model, form=ModelForm, formset=BaseGenericInlineFormSet, ct_field="content_type", fk_field="object_id", fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, validate_max=False, for_concrete_model=True, min_num=None, validate_min=False, absolute_max=None)
 
     Returns a ``GenericInlineFormSet`` using
     :func:`~django.forms.models.modelformset_factory`.
@@ -481,6 +481,10 @@ The :mod:`django.contrib.contenttypes.forms` module provides:
     :class:`~django.contrib.contenttypes.fields.GenericForeignKey.for_concrete_model`
     argument on ``GenericForeignKey``.
 
+    .. versionchanged:: 3.2
+
+        The ``absolute_max`` argument was added.
+
 .. module:: django.contrib.contenttypes.admin
 
 Generic relations in admin

+ 4 - 1
docs/releases/3.2.txt

@@ -85,7 +85,10 @@ Minor features
 :mod:`django.contrib.contenttypes`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-* ...
+* The new ``absolute_max`` argument for
+  :func:`~django.contrib.contenttypes.forms.generic_inlineformset_factory`
+  allows customizing the maximum number of forms that can be instantiated when
+  supplying ``POST`` data. See :ref:`formsets-absolute-max` for more details.
 
 :mod:`django.contrib.gis`
 ~~~~~~~~~~~~~~~~~~~~~~~~~

+ 34 - 0
tests/generic_relations/test_forms.py

@@ -237,3 +237,37 @@ id="id_generic_relations-taggeditem-content_type-object_id-1-id"></p>""" % tagge
         self.assertEqual([tag.tag for tag in tags], ['hunts', 'roars'])
         hunts, roars = tags
         self.assertSequenceEqual(lion.tags.order_by('tag'), [hairy, hunts, roars, yellow])
+
+    def test_absolute_max(self):
+        GenericFormSet = generic_inlineformset_factory(TaggedItem, absolute_max=1500)
+        data = {
+            'form-TOTAL_FORMS': '1501',
+            'form-INITIAL_FORMS': '0',
+            'form-MAX_NUM_FORMS': '0',
+        }
+        formset = GenericFormSet(data=data, prefix='form')
+        self.assertIs(formset.is_valid(), False)
+        self.assertEqual(len(formset.forms), 1500)
+        self.assertEqual(
+            formset.non_form_errors(),
+            ['Please submit 1000 or fewer forms.'],
+        )
+
+    def test_absolute_max_with_max_num(self):
+        GenericFormSet = generic_inlineformset_factory(
+            TaggedItem,
+            max_num=20,
+            absolute_max=100,
+        )
+        data = {
+            'form-TOTAL_FORMS': '101',
+            'form-INITIAL_FORMS': '0',
+            'form-MAX_NUM_FORMS': '0',
+        }
+        formset = GenericFormSet(data=data, prefix='form')
+        self.assertIs(formset.is_valid(), False)
+        self.assertEqual(len(formset.forms), 100)
+        self.assertEqual(
+            formset.non_form_errors(),
+            ['Please submit 20 or fewer forms.'],
+        )