1
0
mirror of https://github.com/django/django.git synced 2025-10-23 21:59:11 +00:00

Fixed #6707 -- Added RelatedManager.set() and made descriptors' __set__ use it.

Thanks Anssi Kääriäinen, Carl Meyer, Collin Anderson, and Tim Graham for the reviews.
This commit is contained in:
Loic Bistuer
2015-01-30 01:15:27 +07:00
parent 49516f7158
commit 71ada3a8e6
10 changed files with 350 additions and 100 deletions

View File

@@ -135,12 +135,31 @@ Related objects reference
:class:`~django.db.models.ForeignKey`\s where ``null=True`` and it also
accepts the ``bulk`` keyword argument.
.. method:: set(objs, clear=False)
.. versionadded:: 1.9
Replace the set of related objects::
>>> new_list = [obj1, obj2, obj3]
>>> e.related_set.set(new_list)
This method accepts a ``clear`` argument to control how to perform the
operation. If ``False`` (the default), the elements missing from the
new set are removed using ``remove()`` and only the new ones are added.
If ``clear=True``, the ``clear()`` method is called instead and the
whole set is added at once.
Note that since ``set()`` is a compound operation, it is subject to
race conditions. For instance, new objects may be added to the database
in between the call to ``clear()`` and the call to ``add()``.
.. note::
Note that ``add()``, ``create()``, ``remove()``, and ``clear()`` all
apply database changes immediately for all types of related fields. In
other words, there is no need to call ``save()`` on either end of the
relationship.
Note that ``add()``, ``create()``, ``remove()``, ``clear()``, and
``set()`` all apply database changes immediately for all types of
related fields. In other words, there is no need to call ``save()``
on either end of the relationship.
Also, if you are using :ref:`an intermediate model
<intermediary-manytomany>` for a many-to-many relationship, some of the
@@ -158,6 +177,12 @@ new iterable of objects to it::
>>> e.related_set = new_list
If the foreign key relationship has ``null=True``, then the related manager
will first call ``clear()`` to disassociate any existing objects in the related
set before adding the contents of ``new_list``. Otherwise the objects in
``new_list`` will be added to the existing related object set.
will first disassociate any existing objects in the related set before adding
the contents of ``new_list``. Otherwise the objects in ``new_list`` will be
added to the existing related object set.
.. versionchanged:1.9
In earlier versions, direct assignment used to perform ``clear()`` followed
by ``add()``. It now performs a ``set()`` with the keyword argument
``clear=False``.

View File

@@ -127,7 +127,10 @@ Management Commands
Models
^^^^^^
* ...
* Added the :meth:`RelatedManager.set()
<django.db.models.fields.related.RelatedManager.set()>` method to the related
managers created by ``ForeignKey``, ``GenericForeignKey``, and
``ManyToManyField``.
Signals
^^^^^^^
@@ -192,6 +195,25 @@ used by the egg loader to detect if setuptools was installed. The ``is_usable``
attribute is now removed and the egg loader instead fails at runtime if
setuptools is not installed.
Related set direct assignment
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:ref:`Direct assignment <direct-assignment>`) used to perform a ``clear()``
followed by a call to ``add()``. This caused needlessly large data changes
and prevented using the :data:`~django.db.models.signals.m2m_changed` signal
to track individual changes in many-to-many relations.
Direct assignment now relies on the the new
:meth:`django.db.models.fields.related.RelatedManager.set()` method on
related managers which by default only processes changes between the
existing related set and the one that's newly assigned. The previous behavior
can be restored by replacing direct assignment by a call to ``set()`` with
the keyword argument ``clear=True``.
``ModelForm``, and therefore ``ModelAdmin``, internally rely on direct
assignment for many-to-many relations and as a consequence now use the new
behavior.
Miscellaneous
~~~~~~~~~~~~~

View File

@@ -1190,6 +1190,9 @@ be found in the :doc:`related objects reference </ref/models/relations>`.
``clear()``
Removes all objects from the related object set.
``set(objs)``
Replace the set of related objects.
To assign the members of a related set in one fell swoop, just assign to it
from any iterable object. The iterable can contain object instances, or just
a list of primary key values. For example::