summaryrefslogtreecommitdiff
path: root/tests/invalid_models_tests/test_relative_fields.py
diff options
context:
space:
mode:
authorAkis Kesoglou <akiskesoglou@gmail.com>2014-02-19 20:01:55 +0200
committerAnssi Kääriäinen <akaariai@gmail.com>2014-03-05 22:33:58 +0200
commitc627da0ccc12861163f28177aa7538b420a9d310 (patch)
treed2c3d58f3083bb502f541a9201811e2cdaefd65b /tests/invalid_models_tests/test_relative_fields.py
parent95c74b9d699c29fe808684774548e2864d64665a (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 'tests/invalid_models_tests/test_relative_fields.py')
-rw-r--r--tests/invalid_models_tests/test_relative_fields.py92
1 files changed, 89 insertions, 3 deletions
diff --git a/tests/invalid_models_tests/test_relative_fields.py b/tests/invalid_models_tests/test_relative_fields.py
index 2d54650414..b04f2d4f17 100644
--- a/tests/invalid_models_tests/test_relative_fields.py
+++ b/tests/invalid_models_tests/test_relative_fields.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals
from django.core.checks import Error
from django.db import models
+from django.db.models.fields import FieldDoesNotExist
from django.test.utils import override_settings
from django.test.testcases import skipIfDBFeature
@@ -81,7 +82,9 @@ class RelativeFieldTests(IsolatedModelsTestCase):
Error(
("The model is used as an intermediate model by "
"'invalid_models_tests.Group.field', but it has more than one "
- "foreign key to 'Person', which is ambiguous."),
+ "foreign key to 'Person', which is ambiguous. You must specify "
+ "which foreign key Django should use via the through_fields "
+ "keyword argument."),
hint=('If you want to create a recursive relationship, use '
'ForeignKey("self", symmetrical=False, '
'through="AmbiguousRelationship").'),
@@ -205,8 +208,10 @@ class RelativeFieldTests(IsolatedModelsTestCase):
Error(
("The model is used as an intermediate model by "
"'invalid_models_tests.Person.friends', but it has more than two "
- "foreign keys to 'Person', which is ambiguous."),
- hint=None,
+ "foreign keys to 'Person', which is ambiguous. You must specify "
+ "which two foreign keys Django should use via the through_fields "
+ "keyword argument."),
+ hint='Use through_fields to specify which two foreign keys Django should use.',
obj=InvalidRelationship,
id='fields.E333',
),
@@ -1051,3 +1056,84 @@ class ComplexClashTests(IsolatedModelsTestCase):
),
]
self.assertEqual(errors, expected)
+
+
+class M2mThroughFieldsTests(IsolatedModelsTestCase):
+ def test_m2m_field_argument_validation(self):
+ """
+ Tests that ManyToManyField accepts the ``through_fields`` kwarg
+ only if an intermediary table is specified.
+ """
+ class Fan(models.Model):
+ pass
+
+ self.assertRaisesMessage(
+ ValueError, 'Cannot specify through_fields without a through model',
+ models.ManyToManyField, Fan, through_fields=('f1', 'f2'))
+
+ def test_invalid_m2m_field(self):
+ """
+ Tests that providing invalid source field name to ManyToManyField.through_fields
+ raises FieldDoesNotExist.
+ """
+ class Fan(models.Model):
+ pass
+
+ class Event(models.Model):
+ invitees = models.ManyToManyField(Fan, through='Invitation', through_fields=('invalid_field', 'invitee'))
+
+ class Invitation(models.Model):
+ event = models.ForeignKey(Event)
+ invitee = models.ForeignKey(Fan)
+ inviter = models.ForeignKey(Fan, related_name='+')
+
+ with self.assertRaisesMessage(FieldDoesNotExist, 'invalid_field'):
+ Event().invitees.all()
+
+ def test_invalid_m2m_reverse_field(self):
+ """
+ Tests that providing invalid reverse field name to ManyToManyField.through_fields
+ raises FieldDoesNotExist.
+ """
+ class Fan(models.Model):
+ pass
+
+ class Event(models.Model):
+ invitees = models.ManyToManyField(Fan, through='Invitation', through_fields=('event', 'invalid_field'))
+
+ class Invitation(models.Model):
+ event = models.ForeignKey(Event)
+ invitee = models.ForeignKey(Fan)
+ inviter = models.ForeignKey(Fan, related_name='+')
+
+ with self.assertRaisesMessage(FieldDoesNotExist, 'invalid_field'):
+ Event().invitees.all()
+
+ def test_explicit_field_names(self):
+ """
+ Tests that if ``through_fields`` kwarg is given, it must specify both
+ link fields of the intermediary table.
+ """
+ class Fan(models.Model):
+ pass
+
+ class Event(models.Model):
+ invitees = models.ManyToManyField(Fan, through='Invitation', through_fields=(None, 'invitee'))
+
+ class Invitation(models.Model):
+ event = models.ForeignKey(Event)
+ invitee = models.ForeignKey(Fan)
+ inviter = models.ForeignKey(Fan, related_name='+')
+
+ field = Event._meta.get_field('invitees')
+ errors = field.check(from_model=Event)
+ expected = [
+ Error(
+ ("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 "
+ "'invalid_models_tests.Invitation'."),
+ hint=None,
+ obj=field,
+ id='fields.E337')]
+ self.assertEqual(expected, errors)