From f9ab543720532400e8b0d490cdbe67ea09ae9c17 Mon Sep 17 00:00:00 2001 From: Andrew Gorcester Date: Wed, 20 Mar 2013 23:27:06 -0700 Subject: Fixed #20084 -- Provided option to validate formset max_num on server. This is provided as a new "validate_max" formset_factory option defaulting to False, since the non-validating behavior of max_num is longstanding, and there is certainly code relying on it. (In fact, even the Django admin relies on it for the case where there are more existing inlines than the given max_num). It may be that at some point we want to deprecate validate_max=False and eventually remove the option, but this commit takes no steps in that direction. This also fixes the DoS-prevention absolute_max enforcement so that it causes a form validation error rather than an IndexError, and ensures that absolute_max is always 1000 more than max_num, to prevent surprising changes in behavior with max_num close to absolute_max. Lastly, this commit fixes the previous inconsistency between a regular formset and a model formset in the precedence of max_num and initial data. Previously in a regular formset, if the provided initial data was longer than max_num, it was truncated; in a model formset, all initial forms would be displayed regardless of max_num. Now regular formsets are the same as model formsets; all initial forms are displayed, even if more than max_num. (But if validate_max is True, submitting these forms will result in a "too many forms" validation error!) This combination of behaviors was chosen to keep the max_num validation simple and consistent, and avoid silent data loss due to truncation of initial data. Thanks to Preston for discussion of the design choices. --- docs/ref/forms/formsets.txt | 16 ++++++++++++++++ docs/ref/forms/index.txt | 1 + docs/ref/forms/models.txt | 15 ++++++++------- 3 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 docs/ref/forms/formsets.txt (limited to 'docs/ref/forms') diff --git a/docs/ref/forms/formsets.txt b/docs/ref/forms/formsets.txt new file mode 100644 index 0000000000..0ab2590fce --- /dev/null +++ b/docs/ref/forms/formsets.txt @@ -0,0 +1,16 @@ +==================== +Formset Functions +==================== + +.. module:: django.forms.formsets + :synopsis: Django's functions for building formsets. + +.. function:: formset_factory(form, formset=BaseFormSet, extra=1, can_order=False, can_delete=False, max_num=None, validate_max=False) + + Returns a ``FormSet`` class for the given ``form`` class. + + See :ref:`formsets` for example usage. + + .. versionchanged:: 1.6 + + The ``validate_max`` parameter was added. diff --git a/docs/ref/forms/index.txt b/docs/ref/forms/index.txt index 446fdb82de..e6edc88ca1 100644 --- a/docs/ref/forms/index.txt +++ b/docs/ref/forms/index.txt @@ -10,5 +10,6 @@ Detailed form API reference. For introductory material, see :doc:`/topics/forms/ api fields models + formsets widgets validation diff --git a/docs/ref/forms/models.txt b/docs/ref/forms/models.txt index f3382d32c7..dd0a422fd0 100644 --- a/docs/ref/forms/models.txt +++ b/docs/ref/forms/models.txt @@ -25,7 +25,7 @@ Model Form Functions See :ref:`modelforms-factory` for example usage. -.. function:: modelformset_factory(model, form=ModelForm, formfield_callback=None, formset=BaseModelFormSet, extra=1, can_delete=False, can_order=False, max_num=None, fields=None, exclude=None, widgets=None) +.. function:: modelformset_factory(model, form=ModelForm, formfield_callback=None, formset=BaseModelFormSet, extra=1, can_delete=False, can_order=False, max_num=None, fields=None, exclude=None, widgets=None, validate_max=False) Returns a ``FormSet`` class for the given ``model`` class. @@ -33,17 +33,18 @@ Model Form Functions ``formfield_callback`` and ``widgets`` are all passed through to :func:`~django.forms.models.modelform_factory`. - Arguments ``formset``, ``extra``, ``max_num``, ``can_order``, and - ``can_delete`` are passed through to ``formset_factory``. See - :ref:`formsets` for details. + Arguments ``formset``, ``extra``, ``max_num``, ``can_order``, + ``can_delete`` and ``validate_max`` are passed through to + :func:`~django.forms.formsets.formset_factory`. See :ref:`formsets` for + details. See :ref:`model-formsets` for example usage. .. versionchanged:: 1.6 - The widgets parameter was added. + The ``widgets`` and the ``validate_max`` parameters were added. -.. function:: inlineformset_factory(parent_model, model, form=ModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, widgets=None) +.. function:: inlineformset_factory(parent_model, model, form=ModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, widgets=None, validate_max=False) Returns an ``InlineFormSet`` using :func:`modelformset_factory` with defaults of ``formset=BaseInlineFormSet``, ``can_delete=True``, and @@ -56,4 +57,4 @@ Model Form Functions .. versionchanged:: 1.6 - The widgets parameter was added. + The ``widgets`` and the ``validate_max`` parameters were added. -- cgit v1.3