From 4c2f546b55c029334d22e69bb29db97f9356faa3 Mon Sep 17 00:00:00 2001 From: Stanislas Guerra Date: Tue, 24 Feb 2015 10:54:05 +0100 Subject: [PATCH] Fixed #24395 -- Ensured inline ModelsForms have an updated related instance. --- django/forms/models.py | 4 ++++ tests/model_formsets/tests.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/django/forms/models.py b/django/forms/models.py index 6889a3e5b4..1a0076eaee 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -904,6 +904,10 @@ class BaseInlineFormSet(BaseModelFormSet): return cls.fk.rel.get_accessor_name(model=cls.model).replace('+', '') def save_new(self, form, commit=True): + # Ensure the latest copy of the related instance is present on each + # form (it may have been saved after the formset was originally + # instantiated). + setattr(form.instance, self.fk.name, self.instance) # Use commit=False so we can assign the parent key afterwards, then # save the object. obj = form.save(commit=False) diff --git a/tests/model_formsets/tests.py b/tests/model_formsets/tests.py index 217a1a1049..07476ebbc3 100644 --- a/tests/model_formsets/tests.py +++ b/tests/model_formsets/tests.py @@ -819,6 +819,38 @@ class ModelFormsetTest(TestCase): formset = AuthorBooksFormSet(data, instance=author, queryset=custom_qs) self.assertTrue(formset.is_valid()) + def test_inline_formsets_with_custom_save_method_related_instance(self): + """ + The ModelForm.save() method should be able to access the related object + if it exists in the database (#24395). + """ + class PoemForm2(forms.ModelForm): + def save(self, commit=True): + poem = super(PoemForm2, self).save(commit=False) + poem.name = "%s by %s" % (poem.name, poem.poet.name) + if commit: + poem.save() + return poem + + PoemFormSet = inlineformset_factory(Poet, Poem, form=PoemForm2, fields="__all__") + data = { + 'poem_set-TOTAL_FORMS': '1', + 'poem_set-INITIAL_FORMS': '0', + 'poem_set-MAX_NUM_FORMS': '', + 'poem_set-0-name': 'Le Lac', + } + poet = Poet() + formset = PoemFormSet(data=data, instance=poet) + self.assertTrue(formset.is_valid()) + + # The Poet instance is saved after the formset instantiation. This + # happens in admin's changeform_view() when adding a new object and + # some inlines in the same request. + poet.name = 'Lamartine' + poet.save() + poem = formset.save()[0] + self.assertEqual(poem.name, 'Le Lac by Lamartine') + def test_inline_formsets_with_wrong_fk_name(self): """ Regression for #23451 """ message = "fk_name 'title' is not a ForeignKey to 'model_formsets.Author'."