diff options
| author | Collin Anderson <cmawebsite@gmail.com> | 2017-03-20 20:26:23 -0400 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2019-01-15 11:12:17 -0500 |
| commit | 769355c76531749d0bc0abad279402e361eaec4e (patch) | |
| tree | 2f9600d8779a41ebb44abde07485cea472227018 /docs | |
| parent | f021c110d02fd7ca32ae56f511b46e5d138b6c73 (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.txt | 35 | ||||
| -rw-r--r-- | docs/releases/2.2.txt | 7 | ||||
| -rw-r--r-- | docs/topics/db/examples/many_to_many.txt | 5 | ||||
| -rw-r--r-- | docs/topics/db/models.txt | 41 |
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') |
