summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorCollin Anderson <cmawebsite@gmail.com>2017-03-20 20:26:23 -0400
committerTim Graham <timograham@gmail.com>2019-01-15 11:12:17 -0500
commit769355c76531749d0bc0abad279402e361eaec4e (patch)
tree2f9600d8779a41ebb44abde07485cea472227018 /docs
parentf021c110d02fd7ca32ae56f511b46e5d138b6c73 (diff)
Fixed #9475 -- Allowed RelatedManager.add(), create(), etc. for m2m with a through model.
Diffstat (limited to 'docs')
-rw-r--r--docs/ref/models/relations.txt35
-rw-r--r--docs/releases/2.2.txt7
-rw-r--r--docs/topics/db/examples/many_to_many.txt5
-rw-r--r--docs/topics/db/models.txt41
4 files changed, 52 insertions, 36 deletions
diff --git a/docs/ref/models/relations.txt b/docs/ref/models/relations.txt
index 353504a58e..6274506a87 100644
--- a/docs/ref/models/relations.txt
+++ b/docs/ref/models/relations.txt
@@ -36,7 +36,7 @@ Related objects reference
In this example, the methods below will be available both on
``topping.pizza_set`` and on ``pizza.toppings``.
- .. method:: add(*objs, bulk=True)
+ .. method:: add(*objs, bulk=True, through_defaults=None)
Adds the specified model objects to the related object set.
@@ -66,7 +66,15 @@ Related objects reference
Using ``add()`` on a relation that already exists won't duplicate the
relation, but it will still trigger signals.
- .. method:: create(**kwargs)
+ Use the ``through_defaults`` argument to specify values for the new
+ :ref:`intermediate model <intermediary-manytomany>` instance(s), if
+ needed.
+
+ .. versionchanged:: 2.2
+
+ The ``through_defaults`` argument was added.
+
+ .. method:: create(through_defaults=None, **kwargs)
Creates a new object, saves it and puts it in the related object set.
Returns the newly created object::
@@ -96,6 +104,14 @@ Related objects reference
parameter ``blog`` to ``create()``. Django figures out that the new
``Entry`` object's ``blog`` field should be set to ``b``.
+ Use the ``through_defaults`` argument to specify values for the new
+ :ref:`intermediate model <intermediary-manytomany>` instance, if
+ needed.
+
+ .. versionchanged:: 2.2
+
+ The ``through_defaults`` argument was added.
+
.. method:: remove(*objs, bulk=True)
Removes the specified model objects from the related object set::
@@ -149,7 +165,7 @@ Related objects reference
For many-to-many relationships, the ``bulk`` keyword argument doesn't
exist.
- .. method:: set(objs, bulk=True, clear=False)
+ .. method:: set(objs, bulk=True, clear=False, through_defaults=None)
Replace the set of related objects::
@@ -172,6 +188,14 @@ Related objects reference
race conditions. For instance, new objects may be added to the database
in between the call to ``clear()`` and the call to ``add()``.
+ Use the ``through_defaults`` argument to specify values for the new
+ :ref:`intermediate model <intermediary-manytomany>` instance(s), if
+ needed.
+
+ .. versionchanged:: 2.2
+
+ The ``through_defaults`` argument was added.
+
.. note::
Note that ``add()``, ``create()``, ``remove()``, ``clear()``, and
@@ -179,11 +203,6 @@ Related objects reference
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, then the
- ``add()``, ``create()``, ``remove()``, and ``set()`` methods are
- disabled.
-
If you use :meth:`~django.db.models.query.QuerySet.prefetch_related`,
the ``add()``, ``remove()``, ``clear()``, and ``set()`` methods clear
the prefetched cache.
diff --git a/docs/releases/2.2.txt b/docs/releases/2.2.txt
index 5d1333ad95..d3c8e9abcc 100644
--- a/docs/releases/2.2.txt
+++ b/docs/releases/2.2.txt
@@ -256,6 +256,13 @@ Models
specified on initialization to ensure that the aggregate function is only
called for each distinct value of ``expressions``.
+* The :meth:`.RelatedManager.add`, :meth:`~.RelatedManager.create`,
+ :meth:`~.RelatedManager.remove`, :meth:`~.RelatedManager.set`,
+ ``get_or_create()``, and ``update_or_create()`` methods are now allowed on
+ many-to-many relationships with intermediate models. The new
+ ``through_defaults`` argument is used to specify values for new intermediate
+ model instance(s).
+
Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/topics/db/examples/many_to_many.txt b/docs/topics/db/examples/many_to_many.txt
index ed4a093964..746fb2f550 100644
--- a/docs/topics/db/examples/many_to_many.txt
+++ b/docs/topics/db/examples/many_to_many.txt
@@ -34,10 +34,7 @@ objects, and a ``Publication`` has multiple ``Article`` objects:
return self.headline
What follows are examples of operations that can be performed using the Python
-API facilities. Note that if you are using :ref:`an intermediate model
-<intermediary-manytomany>` for a many-to-many relationship, some of the related
-manager's methods are disabled, so some of these examples won't work with such
-models.
+API facilities.
Create a few ``Publications``::
diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt
index 1a340a4567..f895db89fa 100644
--- a/docs/topics/db/models.txt
+++ b/docs/topics/db/models.txt
@@ -511,37 +511,31 @@ the intermediate model::
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
-Unlike normal many-to-many fields, you *can't* use ``add()``, ``create()``,
-or ``set()`` to create relationships::
+You can also use ``add()``, ``create()``, or ``set()`` to create relationships,
+as long as your specify ``through_defaults`` for any required fields::
- >>> # The following statements will not work
- >>> beatles.members.add(john)
- >>> beatles.members.create(name="George Harrison")
- >>> beatles.members.set([john, paul, ringo, george])
+ >>> beatles.members.add(john, through_defaults={'date_joined': date(1960, 8, 1)})
+ >>> beatles.members.create(name="George Harrison", through_defaults={'date_joined': date(1960, 8, 1)})
+ >>> beatles.members.set([john, paul, ringo, george], through_defaults={'date_joined': date(1960, 8, 1)})
-Why? You can't just create a relationship between a ``Person`` and a ``Group``
-- you need to specify all the detail for the relationship required by the
-``Membership`` model. The simple ``add``, ``create`` and assignment calls
-don't provide a way to specify this extra detail. As a result, they are
-disabled for many-to-many relationships that use an intermediate model.
-The only way to create this type of relationship is to create instances of the
-intermediate model.
+You may prefer to create instances of the intermediate model directly.
-The :meth:`~django.db.models.fields.related.RelatedManager.remove` method is
-disabled for similar reasons. For example, if the custom through table defined
-by the intermediate model does not enforce uniqueness on the
-``(model1, model2)`` pair, a ``remove()`` call would not provide enough
-information as to which intermediate model instance should be deleted::
+If the custom through table defined by the intermediate model does not enforce
+uniqueness on the ``(model1, model2)`` pair, allowing multiple values, the
+:meth:`~django.db.models.fields.related.RelatedManager.remove` call will
+remove all intermediate model instances::
>>> Membership.objects.create(person=ringo, group=beatles,
... date_joined=date(1968, 9, 4),
... invite_reason="You've been gone for a month and we miss you.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]>
- >>> # This will not work because it cannot tell which membership to remove
+ >>> # This deletes both of the intermediate model instances for Ringo Starr
>>> beatles.members.remove(ringo)
+ >>> beatles.members.all()
+ <QuerySet [<Person: Paul McCartney>]>
-However, the :meth:`~django.db.models.fields.related.RelatedManager.clear`
+The :meth:`~django.db.models.fields.related.RelatedManager.clear`
method can be used to remove all many-to-many relationships for an instance::
>>> # Beatles have broken up
@@ -550,10 +544,9 @@ method can be used to remove all many-to-many relationships for an instance::
>>> Membership.objects.all()
<QuerySet []>
-Once you have established the many-to-many relationships by creating instances
-of your intermediate model, you can issue queries. Just as with normal
-many-to-many relationships, you can query using the attributes of the
-many-to-many-related model::
+Once you have established the many-to-many relationships, you can issue
+queries. Just as with normal many-to-many relationships, you can query using
+the attributes of the many-to-many-related model::
# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')