Commit 65e03a42 authored by Tim Graham's avatar Tim Graham
Browse files

Fixed #10284 -- ModelFormSet.save(commit=False) no longer deletes objects

Thanks laureline.guerin@ and Wedg.
parent 311c1d28
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -717,6 +717,7 @@ class BaseModelFormSet(BaseFormSet):
            obj = self._existing_object(pk_value)
            if form in forms_to_delete:
                self.deleted_objects.append(obj)
                if commit:
                    obj.delete()
                continue
            if form.has_changed():
+5 −0
Original line number Diff line number Diff line
@@ -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<django.forms.models.BaseModelFormSet>`'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
==========================

+26 −8
Original line number Diff line number Diff line
@@ -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<django.forms.models.BaseModelFormSet>`,
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
    <django.forms.models.BaseModelFormSet.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
-------------------------------------
+7 −0
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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)