diff --git a/django/forms/models.py b/django/forms/models.py index 1d3bec1635..2d1ec96306 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -717,7 +717,8 @@ class BaseModelFormSet(BaseFormSet): obj = self._existing_object(pk_value) if form in forms_to_delete: self.deleted_objects.append(obj) - obj.delete() + if commit: + obj.delete() continue if form.has_changed(): self.changed_objects.append((obj, form.changed_data)) diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index a7ab751dd4..bec24c94dc 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -94,6 +94,11 @@ Miscellaneous have a custom :class:`~django.core.files.uploadhandler.FileUploadHandler` that implements ``new_file()``, be sure it accepts this new parameter. +* :class:`ModelFormSet`'s no longer + delete instances when ``save(commit=False)`` is called. See + :attr:`~django.forms.formsets.BaseFormSet.can_delete` for instructions on how + to manually delete objects from deleted forms. + Features deprecated in 1.7 ========================== diff --git a/docs/topics/forms/formsets.txt b/docs/topics/forms/formsets.txt index 470d9f52e4..8be6e10ff6 100644 --- a/docs/topics/forms/formsets.txt +++ b/docs/topics/forms/formsets.txt @@ -3,7 +3,10 @@ Formsets ======== -.. class:: django.forms.formsets.BaseFormSet +.. module:: django.forms.formsets + :synopsis: An abstraction for working with multiple forms on the same page. + +.. class:: BaseFormSet A formset is a layer of abstraction to work with multiple forms on the same page. It can be best compared to a data grid. Let's say you have the following @@ -164,9 +167,7 @@ As we can see, ``formset.errors`` is a list whose entries correspond to the forms in the formset. Validation was performed for each of the two forms, and the expected error message appears for the second item. -.. currentmodule:: django.forms.formsets.BaseFormSet - -.. method:: total_error_count(self) +.. method:: BaseFormSet.total_error_count(self) .. versionadded:: 1.6 @@ -353,6 +354,8 @@ formsets and deletion of forms from a formset. ``can_order`` ~~~~~~~~~~~~~ +.. attribute:: BaseFormSet.can_order + Default: ``False`` Lets you create a formset with the ability to order:: @@ -411,6 +414,8 @@ happen when the user changes these values:: ``can_delete`` ~~~~~~~~~~~~~~ +.. attribute:: BaseFormSet.can_delete + Default: ``False`` Lets you create a formset with the ability to select forms for deletion:: @@ -463,10 +468,23 @@ delete fields you can access them with ``deleted_forms``:: If you are using a :class:`ModelFormSet`, model instances for deleted forms will be deleted when you call -``formset.save()``. On the other hand, if you are using a plain ``FormSet``, -it's up to you to handle ``formset.deleted_forms``, perhaps in your formset's -``save()`` method, as there's no general notion of what it means to delete a -form. +``formset.save()``. + +.. versionchanged:: 1.7 + + If you call ``formset.save(commit=False)``, objects will not be deleted + automatically. You'll need to call ``delete()`` on each of the + :attr:`formset.deleted_objects + ` to actually delete + them:: + + >>> instances = formset.save(commit=False) + >>> for obj in formset.deleted_objects: + ... obj.delete() + +On the other hand, if you are using a plain ``FormSet``, it's up to you to +handle ``formset.deleted_forms``, perhaps in your formset's ``save()`` method, +as there's no general notion of what it means to delete a form. Adding additional fields to a formset ------------------------------------- diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt index 0f3c5bb815..4ef7a6f074 100644 --- a/docs/topics/forms/modelforms.txt +++ b/docs/topics/forms/modelforms.txt @@ -825,6 +825,13 @@ to the database. If your formset contains a ``ManyToManyField``, you'll also need to call ``formset.save_m2m()`` to ensure the many-to-many relationships are saved properly. +After calling ``save()``, your model formset will have three new attributes +containing the formset's changes: + +.. attribute:: models.BaseModelFormSet.changed_objects +.. attribute:: models.BaseModelFormSet.deleted_objects +.. attribute:: models.BaseModelFormSet.new_objects + .. _model-formsets-max-num: Limiting the number of editable objects diff --git a/tests/model_formsets/tests.py b/tests/model_formsets/tests.py index 4411bbf59a..f66b5abb63 100644 --- a/tests/model_formsets/tests.py +++ b/tests/model_formsets/tests.py @@ -32,6 +32,9 @@ class DeletionTests(TestCase): 'form-0-DELETE': 'on', } formset = PoetFormSet(data, queryset=Poet.objects.all()) + formset.save(commit=False) + self.assertEqual(Poet.objects.count(), 1) + formset.save() self.assertTrue(formset.is_valid()) self.assertEqual(Poet.objects.count(), 0)