mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 17:47:04 +03:00
Only catch TypeError/ValueError for object lookups (#6028)
* Only catch TypeError/ValueError for object lookups * Test wrapped TypeError/ValueError handling * Raise NotImplementedError in tests instead of pass
This commit is contained in:
parent
a628a2dbce
commit
38b3d0109b
|
@ -1,6 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import sys
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
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__
|
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):
|
class Hyperlink(six.text_type):
|
||||||
"""
|
"""
|
||||||
A string like object that additionally has an associated name.
|
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_value = view_kwargs[self.lookup_url_kwarg]
|
||||||
lookup_kwargs = {self.lookup_field: lookup_value}
|
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):
|
def get_url(self, obj, view_name, request, format):
|
||||||
"""
|
"""
|
||||||
|
@ -346,7 +370,7 @@ class HyperlinkedRelatedField(RelatedField):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return self.get_object(match.view_name, match.args, match.kwargs)
|
return self.get_object(match.view_name, match.args, match.kwargs)
|
||||||
except (ObjectDoesNotExist, TypeError, ValueError):
|
except (ObjectDoesNotExist, ObjectValueError, ObjectTypeError):
|
||||||
self.fail('does_not_exist')
|
self.fail('does_not_exist')
|
||||||
|
|
||||||
def to_representation(self, value):
|
def to_representation(self, value):
|
||||||
|
|
|
@ -197,6 +197,36 @@ class TestHyperlinkedRelatedField(APISimpleTestCase):
|
||||||
msg = excinfo.value.detail[0]
|
msg = excinfo.value.detail[0]
|
||||||
assert msg == 'Invalid hyperlink - Object does not exist.'
|
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):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
field = Field(view_name='example', queryset=self.queryset)
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
field.to_internal_value('http://example.org/example/doesnotexist/')
|
||||||
|
|
||||||
|
def hyperlinked_related_queryset_error(self, exc_type):
|
||||||
|
class QuerySet:
|
||||||
|
def get(self, *args, **kwargs):
|
||||||
|
raise exc_type
|
||||||
|
|
||||||
|
field = serializers.HyperlinkedRelatedField(
|
||||||
|
view_name='example',
|
||||||
|
lookup_field='name',
|
||||||
|
queryset=QuerySet(),
|
||||||
|
)
|
||||||
|
with pytest.raises(serializers.ValidationError) as excinfo:
|
||||||
|
field.to_internal_value('http://example.org/example/doesnotexist/')
|
||||||
|
msg = excinfo.value.detail[0]
|
||||||
|
assert msg == 'Invalid hyperlink - Object does not exist.'
|
||||||
|
|
||||||
|
def test_hyperlinked_related_queryset_type_error(self):
|
||||||
|
self.hyperlinked_related_queryset_error(TypeError)
|
||||||
|
|
||||||
|
def test_hyperlinked_related_queryset_value_error(self):
|
||||||
|
self.hyperlinked_related_queryset_error(ValueError)
|
||||||
|
|
||||||
|
|
||||||
class TestHyperlinkedIdentityField(APISimpleTestCase):
|
class TestHyperlinkedIdentityField(APISimpleTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user