From 18c5ba07cc81be993941ecc2ecc17923b401b66f Mon Sep 17 00:00:00 2001 From: Shawn Dong Date: Mon, 4 Jul 2022 10:45:28 -0700 Subject: [PATCH] Fixed #33822 -- Fixed save() crash on model formsets when not created by modelformset_factory(). Thanks Claude Paroz for the report. Regression in e87f57fdb8dcdabc452bd15abd015bf6c9b1f7a8. --- django/forms/models.py | 1 + tests/model_formsets/tests.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/django/forms/models.py b/django/forms/models.py index 8a4390fc67..192d9fad94 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -657,6 +657,7 @@ class BaseModelFormSet(BaseFormSet): """ model = None + edit_only = False # Set of fields that must be unique among forms of this set. unique_fields = set() diff --git a/tests/model_formsets/tests.py b/tests/model_formsets/tests.py index a456e1a65e..2c8710b80e 100644 --- a/tests/model_formsets/tests.py +++ b/tests/model_formsets/tests.py @@ -6,6 +6,7 @@ from decimal import Decimal from django import forms from django.core.exceptions import ImproperlyConfigured from django.db import models +from django.forms.formsets import formset_factory from django.forms.models import ( BaseModelFormSet, _get_foreign_key, @@ -2066,6 +2067,36 @@ class ModelFormsetTest(TestCase): formset.save() self.assertCountEqual(Author.objects.all(), [charles, walt]) + def test_edit_only_formset_factory_with_basemodelformset(self): + charles = Author.objects.create(name="Charles Baudelaire") + + class AuthorForm(forms.ModelForm): + class Meta: + model = Author + fields = "__all__" + + class BaseAuthorFormSet(BaseModelFormSet): + def __init__(self, *args, **kwargs): + self.model = Author + super().__init__(*args, **kwargs) + + AuthorFormSet = formset_factory(AuthorForm, formset=BaseAuthorFormSet) + data = { + "form-TOTAL_FORMS": "2", + "form-INITIAL_FORMS": "1", + "form-MAX_NUM_FORMS": "0", + "form-0-id": charles.pk, + "form-0-name": "Shawn Dong", + "form-1-name": "Walt Whitman", + } + formset = AuthorFormSet(data) + self.assertIs(formset.is_valid(), True) + formset.save() + self.assertEqual(Author.objects.count(), 2) + charles.refresh_from_db() + self.assertEqual(charles.name, "Shawn Dong") + self.assertEqual(Author.objects.count(), 2) + class TestModelFormsetOverridesTroughFormMeta(TestCase): def test_modelformset_factory_widgets(self):