diff options
| author | Simon Willison <simonw@eventbrite.com> | 2018-07-18 15:21:40 -0700 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2018-08-22 12:07:29 -0400 |
| commit | 586a9dc4295357de1f5ad0590ad34bf2bc008f79 (patch) | |
| tree | c416257a9176de603d79b12f1f99e28c72725735 | |
| parent | f2d5dafec93e6b3100f004c559ebe21e2b783ae7 (diff) | |
Fixed #26352 -- Made system check allow ManyToManyField to target the same model if through_fields differs.
| -rw-r--r-- | django/db/models/base.py | 7 | ||||
| -rw-r--r-- | docs/ref/checks.txt | 4 | ||||
| -rw-r--r-- | tests/invalid_models_tests/test_models.py | 24 |
3 files changed, 29 insertions, 6 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py index 9cc1af0171..11a2d2a264 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -1301,12 +1301,13 @@ class Model(metaclass=ModelBase): fields = (f for f in fields if isinstance(f.remote_field.through, ModelBase)) for f in fields: - signature = (f.remote_field.model, cls, f.remote_field.through) + signature = (f.remote_field.model, cls, f.remote_field.through, f.remote_field.through_fields) if signature in seen_intermediary_signatures: errors.append( checks.Error( - "The model has two many-to-many relations through " - "the intermediate model '%s'." % f.remote_field.through._meta.label, + "The model has two identical many-to-many relations " + "through the intermediate model '%s'." % + f.remote_field.through._meta.label, obj=cls, id='models.E003', ) diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt index a84d9b60b6..42296f65c9 100644 --- a/docs/ref/checks.txt +++ b/docs/ref/checks.txt @@ -252,8 +252,8 @@ Models * **models.E001**: ``<swappable>`` is not of the form ``app_label.app_name``. * **models.E002**: ``<SETTING>`` references ``<model>``, which has not been installed, or is abstract. -* **models.E003**: The model has two many-to-many relations through the - intermediate model ``<app_label>.<model>``. +* **models.E003**: The model has two identical many-to-many relations through + the intermediate model ``<app_label>.<model>``. * **models.E004**: ``id`` can only be used as a field name if the field also sets ``primary_key=True``. * **models.E005**: The field ``<field name>`` from parent model ``<model>`` diff --git a/tests/invalid_models_tests/test_models.py b/tests/invalid_models_tests/test_models.py index 9dd2fd1f06..709d73d6c8 100644 --- a/tests/invalid_models_tests/test_models.py +++ b/tests/invalid_models_tests/test_models.py @@ -771,13 +771,35 @@ class OtherModelTests(SimpleTestCase): self.assertEqual(Group.check(), [ Error( - "The model has two many-to-many relations through " + "The model has two identical many-to-many relations through " "the intermediate model 'invalid_models_tests.Membership'.", obj=Group, id='models.E003', ) ]) + def test_two_m2m_through_same_model_with_different_through_fields(self): + class Country(models.Model): + pass + + class ShippingMethod(models.Model): + to_countries = models.ManyToManyField( + Country, through='ShippingMethodPrice', + through_fields=('method', 'to_country'), + ) + from_countries = models.ManyToManyField( + Country, through='ShippingMethodPrice', + through_fields=('method', 'from_country'), + related_name='+', + ) + + class ShippingMethodPrice(models.Model): + method = models.ForeignKey(ShippingMethod, models.CASCADE) + to_country = models.ForeignKey(Country, models.CASCADE) + from_country = models.ForeignKey(Country, models.CASCADE) + + self.assertEqual(ShippingMethod.check(), []) + def test_missing_parent_link(self): msg = 'Add parent_link=True to invalid_models_tests.ParkingLot.parent.' with self.assertRaisesMessage(ImproperlyConfigured, msg): |
