Browse Source

Fixed #14642 -- Fixed generic inline formsets crash when using save_as_new=True.

Tomer Chachamu 7 years ago
parent
commit
9bc4d90d1a
2 changed files with 44 additions and 1 deletions
  1. 7 1
      django/contrib/contenttypes/forms.py
  2. 37 0
      tests/generic_relations/test_forms.py

+ 7 - 1
django/contrib/contenttypes/forms.py

@@ -9,7 +9,7 @@ class BaseGenericInlineFormSet(BaseModelFormSet):
     A formset for generic inline objects to a parent.
     """
 
-    def __init__(self, data=None, files=None, instance=None, save_as_new=None,
+    def __init__(self, data=None, files=None, instance=None, save_as_new=False,
                  prefix=None, queryset=None, **kwargs):
         opts = self.model._meta
         self.instance = instance
@@ -17,6 +17,7 @@ class BaseGenericInlineFormSet(BaseModelFormSet):
             opts.app_label + '-' + opts.model_name + '-' +
             self.ct_field.name + '-' + self.ct_fk_field.name
         )
+        self.save_as_new = save_as_new
         if self.instance is None or self.instance.pk is None:
             qs = self.model._default_manager.none()
         else:
@@ -29,6 +30,11 @@ class BaseGenericInlineFormSet(BaseModelFormSet):
             })
         super().__init__(queryset=qs, data=data, files=files, prefix=prefix, **kwargs)
 
+    def initial_form_count(self):
+        if self.save_as_new:
+            return 0
+        return super().initial_form_count()
+
     @classmethod
     def get_default_prefix(cls):
         opts = cls.model._meta

+ 37 - 0
tests/generic_relations/test_forms.py

@@ -200,3 +200,40 @@ id="id_generic_relations-taggeditem-content_type-object_id-1-id" /></p>""" % tag
         self.assertTrue(formset.is_valid())
         new_obj, = formset.save()
         self.assertNotIsInstance(new_obj.obj, ProxyRelatedModel)
+
+    def test_initial_count(self):
+        GenericFormSet = generic_inlineformset_factory(TaggedItem)
+        data = {
+            'form-TOTAL_FORMS': '3',
+            'form-INITIAL_FORMS': '3',
+            'form-MAX_NUM_FORMS': '',
+        }
+        formset = GenericFormSet(data=data, prefix='form')
+        self.assertEqual(formset.initial_form_count(), 3)
+        formset = GenericFormSet(data=data, prefix='form', save_as_new=True)
+        self.assertEqual(formset.initial_form_count(), 0)
+
+    def test_save_as_new(self):
+        """
+        The save_as_new parameter creates new items that are associated with
+        the object.
+        """
+        lion = Animal.objects.create(common_name='Lion', latin_name='Panthera leo')
+        yellow = lion.tags.create(tag='yellow')
+        hairy = lion.tags.create(tag='hairy')
+        GenericFormSet = generic_inlineformset_factory(TaggedItem)
+        data = {
+            'form-TOTAL_FORMS': '3',
+            'form-INITIAL_FORMS': '2',
+            'form-MAX_NUM_FORMS': '',
+            'form-0-id': str(yellow.pk),
+            'form-0-tag': 'hunts',
+            'form-1-id': str(hairy.pk),
+            'form-1-tag': 'roars',
+        }
+        formset = GenericFormSet(data, instance=lion, prefix='form', save_as_new=True)
+        self.assertTrue(formset.is_valid())
+        tags = formset.save()
+        self.assertEqual([tag.tag for tag in tags], ['hunts', 'roars'])
+        hunts, roars = tags
+        self.assertSequenceEqual(lion.tags.order_by('tag'), [hairy, hunts, roars, yellow])