diff --git a/django/contrib/contenttypes/generic.py b/django/contrib/contenttypes/generic.py index 186f39068d7..9db672c8a33 100644 --- a/django/contrib/contenttypes/generic.py +++ b/django/contrib/contenttypes/generic.py @@ -415,13 +415,12 @@ class BaseGenericInlineFormSet(BaseModelFormSet): )) def save_new(self, form, commit=True): - kwargs = { - self.ct_field.get_attname(): ContentType.objects.get_for_model( - self.instance, for_concrete_model=self.for_concrete_model).pk, - self.ct_fk_field.get_attname(): self.instance.pk, - } - new_obj = self.model(**kwargs) - return save_instance(form, new_obj, commit=commit) + setattr(form.instance, self.ct_field.get_attname(), + ContentType.objects.get_for_model(self.instance).pk) + setattr(form.instance, self.ct_fk_field.get_attname(), + self.instance.pk) + return form.save(commit=commit) + def generic_inlineformset_factory(model, form=ModelForm, formset=BaseGenericInlineFormSet, diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py index 253eb76e328..dde00ccc8ac 100644 --- a/tests/generic_relations/tests.py +++ b/tests/generic_relations/tests.py @@ -306,6 +306,32 @@ class GenericInlineFormsetTest(TestCase): form = Formset().forms[0] self.assertIsInstance(form['tag'].field.widget, CustomWidget) + def test_save_new_uses_form_save(self): + """ + Regression for #16260: save_new should call form.save() + """ + class SaveTestForm(forms.ModelForm): + def save(self, *args, **kwargs): + self.instance.saved_by = "custom method" + return super(SaveTestForm, self).save(*args, **kwargs) + + Formset = generic_inlineformset_factory( + ForProxyModelModel, fields='__all__', form=SaveTestForm) + + instance = ProxyRelatedModel.objects.create() + + data = { + 'form-TOTAL_FORMS': '1', + 'form-INITIAL_FORMS': '0', + 'form-MAX_NUM_FORMS': '', + 'form-0-title': 'foo', + } + + formset = Formset(data, instance=instance, prefix='form') + self.assertTrue(formset.is_valid()) + new_obj = formset.save()[0] + self.assertEqual(new_obj.saved_by, "custom method") + def test_save_new_for_proxy(self): Formset = generic_inlineformset_factory(ForProxyModelModel, fields='__all__', for_concrete_model=False)