summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Kavanaugh <alex@kavdev.io>2017-05-01 16:58:28 -0700
committerTim Graham <timograham@gmail.com>2017-05-03 08:59:41 -0400
commit008ba77dfd23576a8080f05e3c45a19da73b20ba (patch)
tree675f94fd9bd7813e0cb27dcccb58ab3c663c7d6f
parentc5b742106834dd295279f22dab91a8353ddcb8af (diff)
[1.11.x] Fixed #28159 -- Fixed BaseInlineFormSet._construct_form() crash when using save_as_new.
Regression in 4a246a02bdcbc13b15480c014f51cb0682af7c1e. Backport of 362fba87c9bb4f88542ba82ce4a732fed2634be7 from master
-rw-r--r--django/forms/models.py7
-rw-r--r--docs/releases/1.11.1.txt3
-rw-r--r--tests/model_formsets/tests.py9
3 files changed, 16 insertions, 3 deletions
diff --git a/django/forms/models.py b/django/forms/models.py
index af324c2b27..ed9df60321 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -894,12 +894,17 @@ class BaseInlineFormSet(BaseModelFormSet):
def _construct_form(self, i, **kwargs):
form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
if self.save_as_new:
+ mutable = getattr(form.data, '_mutable', None)
+ # Allow modifying an immutable QueryDict.
+ if mutable is not None:
+ form.data._mutable = True
# Remove the primary key from the form's data, we are only
# creating new instances
form.data[form.add_prefix(self._pk_field.name)] = None
-
# Remove the foreign key from the form's data
form.data[form.add_prefix(self.fk.name)] = None
+ if mutable is not None:
+ form.data._mutable = mutable
# Set the fk value here so that the form can do its validation.
fk_value = self.instance.pk
diff --git a/docs/releases/1.11.1.txt b/docs/releases/1.11.1.txt
index 9a9d96bf46..727ce94751 100644
--- a/docs/releases/1.11.1.txt
+++ b/docs/releases/1.11.1.txt
@@ -81,3 +81,6 @@ Bugfixes
* Fixed a regression in choice ordering in form fields with grouped and
non-grouped options (:ticket:`28157`).
+
+* Fixed crash in ``BaseInlineFormSet._construct_form()`` when using
+ ``save_as_new`` (:ticket:`28159`).
diff --git a/tests/model_formsets/tests.py b/tests/model_formsets/tests.py
index 4387fbf52d..bc8cf1cac3 100644
--- a/tests/model_formsets/tests.py
+++ b/tests/model_formsets/tests.py
@@ -12,6 +12,7 @@ from django.forms.models import (
BaseModelFormSet, _get_foreign_key, inlineformset_factory,
modelformset_factory,
)
+from django.http import QueryDict
from django.test import TestCase, skipUnlessDBFeature
from django.utils import six
@@ -702,7 +703,9 @@ class ModelFormsetTest(TestCase):
AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=2, fields="__all__")
Author.objects.create(name='Charles Baudelaire')
- data = {
+ # An immutable QueryDict simulates request.POST.
+ data = QueryDict(mutable=True)
+ data.update({
'book_set-TOTAL_FORMS': '3', # the number of forms rendered
'book_set-INITIAL_FORMS': '2', # the number of forms with initial data
'book_set-MAX_NUM_FORMS': '', # the max number of forms
@@ -711,10 +714,12 @@ class ModelFormsetTest(TestCase):
'book_set-1-id': '2',
'book_set-1-title': 'Les Paradis Artificiels',
'book_set-2-title': '',
- }
+ })
+ data._mutable = False
formset = AuthorBooksFormSet(data, instance=Author(), save_as_new=True)
self.assertTrue(formset.is_valid())
+ self.assertIs(data._mutable, False)
new_author = Author.objects.create(name='Charles Baudelaire')
formset = AuthorBooksFormSet(data, instance=new_author, save_as_new=True)