Fixed #28159 -- Fixed BaseInlineFormSet._construct_form() crash when using save_as_new.

Regression in 4a246a02bd.
This commit is contained in:
Alexander Kavanaugh 2017-05-01 16:58:28 -07:00 committed by Tim Graham
parent 9b2d47bcde
commit 362fba87c9
3 changed files with 16 additions and 3 deletions

View File

@ -884,12 +884,17 @@ class BaseInlineFormSet(BaseModelFormSet):
def _construct_form(self, i, **kwargs): def _construct_form(self, i, **kwargs):
form = super()._construct_form(i, **kwargs) form = super()._construct_form(i, **kwargs)
if self.save_as_new: 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 # Remove the primary key from the form's data, we are only
# creating new instances # creating new instances
form.data[form.add_prefix(self._pk_field.name)] = None form.data[form.add_prefix(self._pk_field.name)] = None
# Remove the foreign key from the form's data # Remove the foreign key from the form's data
form.data[form.add_prefix(self.fk.name)] = None 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. # Set the fk value here so that the form can do its validation.
fk_value = self.instance.pk fk_value = self.instance.pk

View File

@ -81,3 +81,6 @@ Bugfixes
* Fixed a regression in choice ordering in form fields with grouped and * Fixed a regression in choice ordering in form fields with grouped and
non-grouped options (:ticket:`28157`). non-grouped options (:ticket:`28157`).
* Fixed crash in ``BaseInlineFormSet._construct_form()`` when using
``save_as_new`` (:ticket:`28159`).

View File

@ -10,6 +10,7 @@ from django.forms.models import (
BaseModelFormSet, _get_foreign_key, inlineformset_factory, BaseModelFormSet, _get_foreign_key, inlineformset_factory,
modelformset_factory, modelformset_factory,
) )
from django.http import QueryDict
from django.test import TestCase, skipUnlessDBFeature from django.test import TestCase, skipUnlessDBFeature
from .models import ( from .models import (
@ -699,7 +700,9 @@ class ModelFormsetTest(TestCase):
AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=2, fields="__all__") AuthorBooksFormSet = inlineformset_factory(Author, Book, can_delete=False, extra=2, fields="__all__")
Author.objects.create(name='Charles Baudelaire') 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-TOTAL_FORMS': '3', # the number of forms rendered
'book_set-INITIAL_FORMS': '2', # the number of forms with initial data 'book_set-INITIAL_FORMS': '2', # the number of forms with initial data
'book_set-MAX_NUM_FORMS': '', # the max number of forms 'book_set-MAX_NUM_FORMS': '', # the max number of forms
@ -708,10 +711,12 @@ class ModelFormsetTest(TestCase):
'book_set-1-id': '2', 'book_set-1-id': '2',
'book_set-1-title': 'Les Paradis Artificiels', 'book_set-1-title': 'Les Paradis Artificiels',
'book_set-2-title': '', 'book_set-2-title': '',
} })
data._mutable = False
formset = AuthorBooksFormSet(data, instance=Author(), save_as_new=True) formset = AuthorBooksFormSet(data, instance=Author(), save_as_new=True)
self.assertTrue(formset.is_valid()) self.assertTrue(formset.is_valid())
self.assertIs(data._mutable, False)
new_author = Author.objects.create(name='Charles Baudelaire') new_author = Author.objects.create(name='Charles Baudelaire')
formset = AuthorBooksFormSet(data, instance=new_author, save_as_new=True) formset = AuthorBooksFormSet(data, instance=new_author, save_as_new=True)