From 7c834f25e473f9cf21b270512c25db778e7d85f3 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Wed, 13 Jun 2018 12:04:20 -0400 Subject: [PATCH] Only catch TypeError/ValueError for object lookups --- rest_framework/relations.py | 28 ++++++++++++++++++++++++++-- tests/test_relations.py | 9 +++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 17dc763d4..e8a4ec2ac 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -1,6 +1,7 @@ # coding: utf-8 from __future__ import unicode_literals +import sys from collections import OrderedDict from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist @@ -31,6 +32,20 @@ def method_overridden(method_name, klass, instance): return default_method is not getattr(instance, method_name).__func__ +class ObjectValueError(ValueError): + """ + Raised when `queryset.get()` failed due to an underlying `ValueError`. + Wrapping prevents calling code conflating this with unrelated errors. + """ + + +class ObjectTypeError(TypeError): + """ + Raised when `queryset.get()` failed due to an underlying `TypeError`. + Wrapping prevents calling code conflating this with unrelated errors. + """ + + class Hyperlink(six.text_type): """ A string like object that additionally has an associated name. @@ -296,7 +311,16 @@ class HyperlinkedRelatedField(RelatedField): """ lookup_value = view_kwargs[self.lookup_url_kwarg] lookup_kwargs = {self.lookup_field: lookup_value} - return self.get_queryset().get(**lookup_kwargs) + queryset = self.get_queryset() + + try: + return queryset.get(**lookup_kwargs) + except ValueError: + exc = ObjectValueError(str(sys.exc_info()[1])) + six.reraise(type(exc), exc, sys.exc_info()[2]) + except TypeError: + exc = ObjectTypeError(str(sys.exc_info()[1])) + six.reraise(type(exc), exc, sys.exc_info()[2]) def get_url(self, obj, view_name, request, format): """ @@ -346,7 +370,7 @@ class HyperlinkedRelatedField(RelatedField): try: return self.get_object(match.view_name, match.args, match.kwargs) - except (ObjectDoesNotExist, TypeError, ValueError): + except (ObjectDoesNotExist, ObjectValueError, ObjectTypeError): self.fail('does_not_exist') def to_representation(self, value): diff --git a/tests/test_relations.py b/tests/test_relations.py index 7c4610301..c2a8adaf2 100644 --- a/tests/test_relations.py +++ b/tests/test_relations.py @@ -197,6 +197,15 @@ class TestHyperlinkedRelatedField(APISimpleTestCase): msg = excinfo.value.detail[0] assert msg == 'Invalid hyperlink - Object does not exist.' + def test_hyperlinked_related_internal_type_error(self): + class Field(serializers.HyperlinkedRelatedField): + def get_object(self, incorrect, signature): + pass + + field = Field(view_name='example', queryset=self.queryset) + with pytest.raises(TypeError): + field.to_internal_value('http://example.org/example/doesnotexist/') + class TestHyperlinkedIdentityField(APISimpleTestCase): def setUp(self):