diff options
| author | Akis Kesoglou <akiskesoglou@gmail.com> | 2014-02-19 20:01:55 +0200 |
|---|---|---|
| committer | Anssi Kääriäinen <akaariai@gmail.com> | 2014-03-05 22:33:58 +0200 |
| commit | c627da0ccc12861163f28177aa7538b420a9d310 (patch) | |
| tree | d2c3d58f3083bb502f541a9201811e2cdaefd65b /docs | |
| parent | 95c74b9d699c29fe808684774548e2864d64665a (diff) | |
Fixed #14549 - Removed restriction of single FKs on intermediary tables
Thanks to Loic Bistuer for review. Minor changes to error messages
done by committer.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/ref/checks.txt | 9 | ||||
| -rw-r--r-- | docs/ref/models/fields.txt | 49 | ||||
| -rw-r--r-- | docs/releases/1.7.txt | 6 | ||||
| -rw-r--r-- | docs/topics/db/models.txt | 32 |
4 files changed, 80 insertions, 16 deletions
diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt index 908a32d4c8..4f023d2844 100644 --- a/docs/ref/checks.txt +++ b/docs/ref/checks.txt @@ -90,10 +90,11 @@ Related Fields * **fields.E330**: ManyToManyFields cannot be unique. * **fields.E331**: Field specifies a many-to-many relation through model ``%s``, which has not been installed. * **fields.E332**: Many-to-many fields with intermediate tables must not be symmetrical. -* **fields.E333**: The model is used as an intermediate model by ``<model>``, but it has more than two foreign keys to ``<model>``, which is ambiguous. -* **fields.E334**: The model is used as an intermediate model by ``<model>``, but it has more than one foreign key from ``<model>``, which is ambiguous. -* **fields.E335**: The model is used as an intermediate model by ``<model>``, but it has more than one foreign key to ``<model>``, which is ambiguous. -* **fields.E336**: The model is used as an intermediary model by ``<model>``, but it does not have foreign key to ``<model>`` or ``<model>``." +* **fields.E333**: The model is used as an intermediate model by ``<model>``, but it has more than two foreign keys to ``<model>``, which is ambiguous. You must specify which two foreign keys Django should use via the through_fields keyword argument. +* **fields.E334**: The model is used as an intermediate model by ``<model>``, but it has more than one foreign key from ``<model>``, which is ambiguous. You must specify which foreign key Django should use via the through_fields keyword argument. +* **fields.E335**: The model is used as an intermediate model by ``<model>``, but it has more than one foreign key to ``<model>``, which is ambiguous. You must specify which foreign key Django should use via the through_fields keyword argument. +* **fields.E336**: The model is used as an intermediary model by ``<model>``, but it does not have foreign key to ``<model>`` or ``<model>``. +* **fields.E337**: The field is given an iterable for through_fields, which does not provide the names for both link fields that Django should use for the relation through <model>. Signals ~~~~~~~ diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt index b3523334c0..ab24dd7e66 100644 --- a/docs/ref/models/fields.txt +++ b/docs/ref/models/fields.txt @@ -1337,6 +1337,55 @@ that control how the relationship functions. :ref:`extra data with a many-to-many relationship <intermediary-manytomany>`. +.. attribute:: ManyToManyField.through_fields + + .. versionadded:: 1.7 + + Only used when a custom intermediary model is specified. Django will + normally determine which fields of the intermediary model to use in order + to establish a many-to-many relationship automatically. However, + consider the following models:: + + from django.db import models + + class Person(models.Model): + name = models.CharField(max_length=50) + + class Group(models.Model): + name = models.CharField(max_length=128) + members = models.ManyToManyField(Person, through='Membership', through_fields=('person', 'group')) + + class Membership(models.Model): + person = models.ForeignKey(Person) + group = models.ForeignKey(Group) + inviter = models.ForeignKey(Person, related_name="membership_invites") + invite_reason = models.CharField(max_length=64) + + ``Membership`` has *two* foreign keys to ``Person`` (``person`` and + ``inviter``), which makes the relationship ambiguous and Django can't know + which one to use. In this case, you must explicitly specify which + foreign keys Django should use using ``through_fields``, as in the example + above. + + ``through_fields`` accepts a 2-tuple ``('field1', 'field2')``, where + ``field1`` is the name of the foreign key to the target model (``person`` + in this case), and ``field2`` the name of the foreign key to the model the + :class:`ManyToManyField` is defined on (``group`` in this case). + + When you have more than one foreign key on an intermediary model to any + (or even both) of the models participating in a many-to-many relationship, + you *must* specify ``through_fields``. This also applies to + :ref:`recursive relationships <recursive-relationships>` + when an intermediary model is used and there are more than two + foreign keys to the model, or you want to explicitly specify which two + Django should use. + + Recursive relationships using an intermediary model are always defined as + non-symmetrical -- that is, with :attr:`symmetrical=False <ManyToManyField.symmetrical>` + -- therefore, there is the concept of a "source" and a "target". In that + case ``'field1'`` will be treated as the "source" of the relationship and + ``'field2'`` as the "target". + .. attribute:: ManyToManyField.db_table The name of the table to create for storing the many-to-many data. If this diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index 096415c5b8..4c0457e7c5 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -658,6 +658,12 @@ Models * You can use a single list for :attr:`~django.db.models.Options.index_together` (rather than a list of lists) when specifying a single set of fields. +* Custom intermediate models having more than one foreign key to any of the + models participating in a many-to-many relationship are now permitted, + provided you explicitly specify which foreign keys should be used by setting + the new :attr:`ManyToManyField.through_fields <django.db.models.ManyToManyField.through_fields>` + argument. + Signals ^^^^^^^ diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt index f5ad7ed95f..4caf9ad736 100644 --- a/docs/topics/db/models.txt +++ b/docs/topics/db/models.txt @@ -434,30 +434,38 @@ something like this:: invite_reason = models.CharField(max_length=64) When you set up the intermediary model, you explicitly specify foreign -keys to the models that are involved in the ManyToMany relation. This +keys to the models that are involved in the many-to-many relationship. This explicit declaration defines how the two models are related. There are a few restrictions on the intermediate model: * Your intermediate model must contain one - and *only* one - foreign key - to the target model (this would be ``Person`` in our example). If you - have more than one foreign key, a validation error will be raised. + to the target model (this would be ``Person`` in our example), or you must + explicitly specify the foreign keys Django should use for the relationship + using :attr:`ManyToManyField.through_fields <ManyToManyField.through_fields>`. + If you have more than one foreign key and ``through_fields`` is not + specified, a validation error will be raised. A similar restriction applies + to the foreign key to the source model (this would be ``Group`` in our + example). -* Your intermediate model must contain one - and *only* one - foreign key - to the source model (this would be ``Group`` in our example). If you - have more than one foreign key, a validation error will be raised. - -* The only exception to this is a model which has a many-to-many - relationship to itself, through an intermediary model. In this - case, two foreign keys to the same model are permitted, but they - will be treated as the two (different) sides of the many-to-many - relation. +* 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 + 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 + must also specify ``through_fields`` as above, or a validation error + will be raised. * When defining a many-to-many relationship from a model to itself, using an intermediary model, you *must* use :attr:`symmetrical=False <ManyToManyField.symmetrical>` (see :ref:`the model field reference <manytomany-arguments>`). +.. versionchanged:: 1.7 + + In Django 1.6 and earlier, intermediate models containing more than one + foreign key to any of the models involved in the many-to-many relationship + used to be prohibited. + 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 creating some many-to-many relationships. You do this by creating instances of |
