mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 01:47:59 +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
 | 
			
		||||
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):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -197,6 +197,36 @@ 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):
 | 
			
		||||
                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):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user