Commit 211bb89e by Tom Christie

Raise Validation Errors when relationships receive incorrect types. Fixes #590.

parent 6385ac51
...@@ -177,7 +177,7 @@ class PrimaryKeyRelatedField(RelatedField): ...@@ -177,7 +177,7 @@ class PrimaryKeyRelatedField(RelatedField):
default_error_messages = { default_error_messages = {
'does_not_exist': _("Invalid pk '%s' - object does not exist."), 'does_not_exist': _("Invalid pk '%s' - object does not exist."),
'invalid': _('Invalid value.'), 'incorrect_type': _('Incorrect type. Expected pk value, received %s.'),
} }
# TODO: Remove these field hacks... # TODO: Remove these field hacks...
...@@ -208,7 +208,8 @@ class PrimaryKeyRelatedField(RelatedField): ...@@ -208,7 +208,8 @@ class PrimaryKeyRelatedField(RelatedField):
msg = self.error_messages['does_not_exist'] % smart_unicode(data) msg = self.error_messages['does_not_exist'] % smart_unicode(data)
raise ValidationError(msg) raise ValidationError(msg)
except (TypeError, ValueError): except (TypeError, ValueError):
msg = self.error_messages['invalid'] received = type(data).__name__
msg = self.error_messages['incorrect_type'] % received
raise ValidationError(msg) raise ValidationError(msg)
def field_to_native(self, obj, field_name): def field_to_native(self, obj, field_name):
...@@ -235,7 +236,7 @@ class ManyPrimaryKeyRelatedField(ManyRelatedField): ...@@ -235,7 +236,7 @@ class ManyPrimaryKeyRelatedField(ManyRelatedField):
default_error_messages = { default_error_messages = {
'does_not_exist': _("Invalid pk '%s' - object does not exist."), 'does_not_exist': _("Invalid pk '%s' - object does not exist."),
'invalid': _('Invalid value.'), 'incorrect_type': _('Incorrect type. Expected pk value, received %s.'),
} }
def prepare_value(self, obj): def prepare_value(self, obj):
...@@ -275,7 +276,8 @@ class ManyPrimaryKeyRelatedField(ManyRelatedField): ...@@ -275,7 +276,8 @@ class ManyPrimaryKeyRelatedField(ManyRelatedField):
msg = self.error_messages['does_not_exist'] % smart_unicode(data) msg = self.error_messages['does_not_exist'] % smart_unicode(data)
raise ValidationError(msg) raise ValidationError(msg)
except (TypeError, ValueError): except (TypeError, ValueError):
msg = self.error_messages['invalid'] received = type(data).__name__
msg = self.error_messages['incorrect_type'] % received
raise ValidationError(msg) raise ValidationError(msg)
### Slug relationships ### Slug relationships
...@@ -333,7 +335,7 @@ class HyperlinkedRelatedField(RelatedField): ...@@ -333,7 +335,7 @@ class HyperlinkedRelatedField(RelatedField):
'incorrect_match': _('Invalid hyperlink - Incorrect URL match'), 'incorrect_match': _('Invalid hyperlink - Incorrect URL match'),
'configuration_error': _('Invalid hyperlink due to configuration error'), 'configuration_error': _('Invalid hyperlink due to configuration error'),
'does_not_exist': _("Invalid hyperlink - object does not exist."), 'does_not_exist': _("Invalid hyperlink - object does not exist."),
'invalid': _('Invalid value.'), 'incorrect_type': _('Incorrect type. Expected url string, received %s.'),
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
...@@ -397,8 +399,8 @@ class HyperlinkedRelatedField(RelatedField): ...@@ -397,8 +399,8 @@ class HyperlinkedRelatedField(RelatedField):
try: try:
http_prefix = value.startswith('http:') or value.startswith('https:') http_prefix = value.startswith('http:') or value.startswith('https:')
except AttributeError: except AttributeError:
msg = self.error_messages['invalid'] msg = self.error_messages['incorrect_type']
raise ValidationError(msg) raise ValidationError(msg % type(value).__name__)
if http_prefix: if http_prefix:
# If needed convert absolute URLs to relative path # If needed convert absolute URLs to relative path
...@@ -434,8 +436,8 @@ class HyperlinkedRelatedField(RelatedField): ...@@ -434,8 +436,8 @@ class HyperlinkedRelatedField(RelatedField):
except ObjectDoesNotExist: except ObjectDoesNotExist:
raise ValidationError(self.error_messages['does_not_exist']) raise ValidationError(self.error_messages['does_not_exist'])
except (TypeError, ValueError): except (TypeError, ValueError):
msg = self.error_messages['invalid'] msg = self.error_messages['incorrect_type']
raise ValidationError(msg) raise ValidationError(msg % type(value).__name__)
return obj return obj
......
...@@ -215,6 +215,13 @@ class HyperlinkedForeignKeyTests(TestCase): ...@@ -215,6 +215,13 @@ class HyperlinkedForeignKeyTests(TestCase):
] ]
self.assertEquals(serializer.data, expected) self.assertEquals(serializer.data, expected)
def test_foreign_key_update_incorrect_type(self):
data = {'url': '/foreignkeysource/1/', 'name': u'source-1', 'target': 2}
instance = ForeignKeySource.objects.get(pk=1)
serializer = ForeignKeySourceSerializer(instance, data=data)
self.assertFalse(serializer.is_valid())
self.assertEquals(serializer.errors, {'target': [u'Incorrect type. Expected url string, received int.']})
def test_reverse_foreign_key_update(self): def test_reverse_foreign_key_update(self):
data = {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/3/']} data = {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/3/']}
instance = ForeignKeyTarget.objects.get(pk=2) instance = ForeignKeyTarget.objects.get(pk=2)
...@@ -227,7 +234,7 @@ class HyperlinkedForeignKeyTests(TestCase): ...@@ -227,7 +234,7 @@ class HyperlinkedForeignKeyTests(TestCase):
expected = [ expected = [
{'url': '/foreignkeytarget/1/', 'name': u'target-1', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/2/', '/foreignkeysource/3/']}, {'url': '/foreignkeytarget/1/', 'name': u'target-1', 'sources': ['/foreignkeysource/1/', '/foreignkeysource/2/', '/foreignkeysource/3/']},
{'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': []}, {'url': '/foreignkeytarget/2/', 'name': u'target-2', 'sources': []},
] ]
self.assertEquals(new_serializer.data, expected) self.assertEquals(new_serializer.data, expected)
serializer.save() serializer.save()
......
...@@ -194,6 +194,13 @@ class PKForeignKeyTests(TestCase): ...@@ -194,6 +194,13 @@ class PKForeignKeyTests(TestCase):
] ]
self.assertEquals(serializer.data, expected) self.assertEquals(serializer.data, expected)
def test_foreign_key_update_incorrect_type(self):
data = {'id': 1, 'name': u'source-1', 'target': 'foo'}
instance = ForeignKeySource.objects.get(pk=1)
serializer = ForeignKeySourceSerializer(instance, data=data)
self.assertFalse(serializer.is_valid())
self.assertEquals(serializer.errors, {'target': [u'Incorrect type. Expected pk value, received str.']})
def test_reverse_foreign_key_update(self): def test_reverse_foreign_key_update(self):
data = {'id': 2, 'name': u'target-2', 'sources': [1, 3]} data = {'id': 2, 'name': u'target-2', 'sources': [1, 3]}
instance = ForeignKeyTarget.objects.get(pk=2) instance = ForeignKeyTarget.objects.get(pk=2)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment