diff options
| author | André Ericson <de.ericson@gmail.com> | 2014-10-04 20:47:26 -0300 |
|---|---|---|
| committer | André Ericson <de.ericson@gmail.com> | 2014-10-04 20:47:26 -0300 |
| commit | 1e5e2a470768549117ac4696ce3e8b4e51d65664 (patch) | |
| tree | 3ef4e3b818974378d435939771bb2d5495ae36aa /tests/invalid_models_tests/test_relative_fields.py | |
| parent | 8c581ff39475c1b3b25d60945cc1c73a7f8eb1be (diff) | |
Fixed #22064 -- Add check for related_name
Validates that related_name is a valid Python id or ends with a '+' and
it's not a keyword. Without a check it passed silently leading to
unpredictable problems.
Thanks Konrad Świat for the initial work.
Diffstat (limited to 'tests/invalid_models_tests/test_relative_fields.py')
| -rw-r--r-- | tests/invalid_models_tests/test_relative_fields.py | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/tests/invalid_models_tests/test_relative_fields.py b/tests/invalid_models_tests/test_relative_fields.py index 4b4c5947f3..9781ecc2ba 100644 --- a/tests/invalid_models_tests/test_relative_fields.py +++ b/tests/invalid_models_tests/test_relative_fields.py @@ -546,6 +546,73 @@ class RelativeFieldTests(IsolatedModelsTestCase): errors = field.check(from_model=Model) self.assertEqual(errors, [expected_error]) + def test_related_field_has_invalid_related_name(self): + digit = 0 + illegal_non_alphanumeric = '!' + whitespace = '\t' + + invalid_related_names = [ + '%s_begins_with_digit' % digit, + '%s_begins_with_illegal_non_alphanumeric' % illegal_non_alphanumeric, + '%s_begins_with_whitespace' % whitespace, + 'contains_%s_illegal_non_alphanumeric' % illegal_non_alphanumeric, + 'contains_%s_whitespace' % whitespace, + 'ends_with_with_illegal_non_alphanumeric_%s' % illegal_non_alphanumeric, + 'ends_with_whitespace_%s' % whitespace, + # Python's keyword + 'with', + ] + + class Parent(models.Model): + pass + + for invalid_related_name in invalid_related_names: + Child = type(str('Child_%s') % str(invalid_related_name), (models.Model,), { + 'parent': models.ForeignKey('Parent', related_name=invalid_related_name), + '__module__': Parent.__module__, + }) + + field = Child._meta.get_field('parent') + errors = Child.check() + expected = [ + Error( + "The name '%s' is invalid related_name for field Child_%s.parent" + % (invalid_related_name, invalid_related_name), + hint="Related name must be a valid Python identifier or end with a '+'", + obj=field, + id='fields.E306', + ), + ] + self.assertEqual(errors, expected) + + def test_related_field_has_valid_related_name(self): + lowercase = 'a' + uppercase = 'A' + digit = 0 + + related_names = [ + '%s_starts_with_lowercase' % lowercase, + '%s_tarts_with_uppercase' % uppercase, + '_starts_with_underscore', + 'contains_%s_digit' % digit, + 'ends_with_plus+', + '_', + '_+', + '+', + ] + + class Parent(models.Model): + pass + + for related_name in related_names: + Child = type(str('Child_%s') % str(related_name), (models.Model,), { + 'parent': models.ForeignKey('Parent', related_name=related_name), + '__module__': Parent.__module__, + }) + + errors = Child.check() + self.assertFalse(errors) + class AccessorClashTests(IsolatedModelsTestCase): |
