1
0
mirror of https://github.com/django/django.git synced 2025-10-24 14:16:09 +00:00

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.
This commit is contained in:
André Ericson
2014-10-04 20:47:26 -03:00
parent 8c581ff394
commit 1e5e2a4707
3 changed files with 90 additions and 0 deletions

View File

@@ -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):