1
0
mirror of https://github.com/django/django.git synced 2025-05-10 17:06:29 +00:00

Fixed #17461 -- Doc'd the presumed order of foreign keys on the intermediary model of a self-referential m2m.

Thanks Giannis Terzopoulos and Sarah Boyce for the reviews.
This commit is contained in:
Clifford Gama 2024-11-03 16:32:55 +02:00 committed by Sarah Boyce
parent 0f5dd0dff3
commit 9d93e35c20
2 changed files with 42 additions and 3 deletions

View File

@ -2041,6 +2041,42 @@ that control how the relationship functions.
prefer Django not to create a backwards relation, set ``related_name`` prefer Django not to create a backwards relation, set ``related_name``
to ``'+'``. to ``'+'``.
.. admonition:: Foreign key order in intermediary models
When defining an asymmetric many-to-many relationship from a model to
itself using an intermediary model without defining
:attr:`through_fields`, the first foreign key in the intermediary model
will be treated as representing the source side of the
``ManyToManyField``, and the second as the target side. For example::
from django.db import models
class Manufacturer(models.Model):
name = models.CharField(max_length=255)
clients = models.ManyToManyField(
"self", symmetrical=False, related_name="suppliers", through="Supply"
)
class Supply(models.Model):
supplier = models.ForeignKey(
Manufacturer, models.CASCADE, related_name="supplies_given"
)
client = models.ForeignKey(
Manufacturer, models.CASCADE, related_name="supplies_received"
)
product = models.CharField(max_length=255)
Here, the ``Manufacturer`` model defines the many-to-many relationship
with ``clients`` in its role as a supplier. Therefore, the ``supplier``
foreign key (the source) must come before the ``client`` foreign key
(the target) in the intermediary ``Supply`` model.
Specifying :attr:`through_fields=("supplier", "client")
<.ManyToManyField.through_fields>` on the ``ManyToManyField`` makes the
order of foreign keys on the ``through`` model irrelevant.
If you don't specify an explicit ``through`` model, there is still an If you don't specify an explicit ``through`` model, there is still an
implicit ``through`` model class you can use to directly access the table implicit ``through`` model class you can use to directly access the table
created to hold the association. It has three fields to link the models, a created to hold the association. It has three fields to link the models, a

View File

@ -533,9 +533,12 @@ There are a few restrictions on the intermediate model:
* For a model which has a many-to-many relationship to itself through an * For a model which has a many-to-many relationship to itself through an
intermediary model, two foreign keys to the same model are permitted, but intermediary model, two foreign keys to the same model are permitted, but
they will be treated as the two (different) sides of the many-to-many they will be treated as the two (different) sides of the many-to-many
relationship. If there are *more* than two foreign keys though, you relationship. If :attr:`~.ManyToManyField.through_fields` is not specified,
must also specify ``through_fields`` as above, or a validation error the first foreign key will be taken to represent the source side of the
will be raised. ``ManyToManyField``, while the second will be taken to represent the target
side. If there are *more* than two foreign keys though, you must specify
:attr:`~.ManyToManyField.through_fields` to explicitly indicate which foreign
keys to use, otherwise a validation error will be raised.
Now that you have set up your :class:`~django.db.models.ManyToManyField` to use Now that you have set up your :class:`~django.db.models.ManyToManyField` to use
your intermediary model (``Membership``, in this case), you're ready to start your intermediary model (``Membership``, in this case), you're ready to start