mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-23 01:57:00 +03:00
Merge pull request #5078 from rooterkyberian/issue-4748
add URL path unquote to HyperlinkedRelatedField.to_internal_value
This commit is contained in:
commit
ee1a9fcef6
|
@ -7,7 +7,9 @@ from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
|
||||||
from django.db.models import Manager
|
from django.db.models import Manager
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import python_2_unicode_compatible, smart_text
|
from django.utils.encoding import (
|
||||||
|
python_2_unicode_compatible, smart_text, uri_to_iri
|
||||||
|
)
|
||||||
from django.utils.six.moves.urllib import parse as urlparse
|
from django.utils.six.moves.urllib import parse as urlparse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
@ -324,6 +326,8 @@ class HyperlinkedRelatedField(RelatedField):
|
||||||
if data.startswith(prefix):
|
if data.startswith(prefix):
|
||||||
data = '/' + data[len(prefix):]
|
data = '/' + data[len(prefix):]
|
||||||
|
|
||||||
|
data = uri_to_iri(data)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
match = resolve(data)
|
match = resolve(data)
|
||||||
except Resolver404:
|
except Resolver404:
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from django.conf.urls import url
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
from django.test import override_settings
|
||||||
from django.utils.datastructures import MultiValueDict
|
from django.utils.datastructures import MultiValueDict
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
@ -87,10 +89,21 @@ class TestProxiedPrimaryKeyRelatedField(APISimpleTestCase):
|
||||||
assert representation == self.instance.pk.int
|
assert representation == self.instance.pk.int
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(ROOT_URLCONF=[
|
||||||
|
url(r'^example/(?P<name>.+)/$', lambda: None, name='example'),
|
||||||
|
])
|
||||||
class TestHyperlinkedRelatedField(APISimpleTestCase):
|
class TestHyperlinkedRelatedField(APISimpleTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
self.queryset = MockQueryset([
|
||||||
|
MockObject(pk=1, name='foobar'),
|
||||||
|
MockObject(pk=2, name='baz qux'),
|
||||||
|
])
|
||||||
self.field = serializers.HyperlinkedRelatedField(
|
self.field = serializers.HyperlinkedRelatedField(
|
||||||
view_name='example', read_only=True)
|
view_name='example',
|
||||||
|
lookup_field='name',
|
||||||
|
lookup_url_kwarg='name',
|
||||||
|
queryset=self.queryset,
|
||||||
|
)
|
||||||
self.field.reverse = mock_reverse
|
self.field.reverse = mock_reverse
|
||||||
self.field._context = {'request': True}
|
self.field._context = {'request': True}
|
||||||
|
|
||||||
|
@ -98,6 +111,20 @@ class TestHyperlinkedRelatedField(APISimpleTestCase):
|
||||||
representation = self.field.to_representation(MockObject(pk=''))
|
representation = self.field.to_representation(MockObject(pk=''))
|
||||||
assert representation is None
|
assert representation is None
|
||||||
|
|
||||||
|
def test_hyperlinked_related_lookup_exists(self):
|
||||||
|
instance = self.field.to_internal_value('http://example.org/example/foobar/')
|
||||||
|
assert instance is self.queryset.items[0]
|
||||||
|
|
||||||
|
def test_hyperlinked_related_lookup_url_encoded_exists(self):
|
||||||
|
instance = self.field.to_internal_value('http://example.org/example/baz%20qux/')
|
||||||
|
assert instance is self.queryset.items[1]
|
||||||
|
|
||||||
|
def test_hyperlinked_related_lookup_does_not_exist(self):
|
||||||
|
with pytest.raises(serializers.ValidationError) as excinfo:
|
||||||
|
self.field.to_internal_value('http://example.org/example/doesnotexist/')
|
||||||
|
msg = excinfo.value.detail[0]
|
||||||
|
assert msg == 'Invalid hyperlink - Object does not exist.'
|
||||||
|
|
||||||
|
|
||||||
class TestHyperlinkedIdentityField(APISimpleTestCase):
|
class TestHyperlinkedIdentityField(APISimpleTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -156,6 +156,7 @@ class TestCustomLookupFields(TestCase):
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
RouterTestModel.objects.create(uuid='123', text='foo bar')
|
RouterTestModel.objects.create(uuid='123', text='foo bar')
|
||||||
|
RouterTestModel.objects.create(uuid='a b', text='baz qux')
|
||||||
|
|
||||||
def test_custom_lookup_field_route(self):
|
def test_custom_lookup_field_route(self):
|
||||||
detail_route = notes_router.urls[-1]
|
detail_route = notes_router.urls[-1]
|
||||||
|
@ -164,12 +165,19 @@ class TestCustomLookupFields(TestCase):
|
||||||
|
|
||||||
def test_retrieve_lookup_field_list_view(self):
|
def test_retrieve_lookup_field_list_view(self):
|
||||||
response = self.client.get('/example/notes/')
|
response = self.client.get('/example/notes/')
|
||||||
assert response.data == [{"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"}]
|
assert response.data == [
|
||||||
|
{"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"},
|
||||||
|
{"url": "http://testserver/example/notes/a%20b/", "uuid": "a b", "text": "baz qux"},
|
||||||
|
]
|
||||||
|
|
||||||
def test_retrieve_lookup_field_detail_view(self):
|
def test_retrieve_lookup_field_detail_view(self):
|
||||||
response = self.client.get('/example/notes/123/')
|
response = self.client.get('/example/notes/123/')
|
||||||
assert response.data == {"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"}
|
assert response.data == {"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"}
|
||||||
|
|
||||||
|
def test_retrieve_lookup_field_url_encoded_detail_view_(self):
|
||||||
|
response = self.client.get('/example/notes/a%20b/')
|
||||||
|
assert response.data == {"url": "http://testserver/example/notes/a%20b/", "uuid": "a b", "text": "baz qux"}
|
||||||
|
|
||||||
|
|
||||||
class TestLookupValueRegex(TestCase):
|
class TestLookupValueRegex(TestCase):
|
||||||
"""
|
"""
|
||||||
|
@ -211,6 +219,10 @@ class TestLookupUrlKwargs(TestCase):
|
||||||
response = self.client.get('/example2/notes/fo/')
|
response = self.client.get('/example2/notes/fo/')
|
||||||
assert response.data == {"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"}
|
assert response.data == {"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"}
|
||||||
|
|
||||||
|
def test_retrieve_lookup_url_encoded_kwarg_detail_view(self):
|
||||||
|
response = self.client.get('/example2/notes/foo%20bar/')
|
||||||
|
assert response.data == {"url": "http://testserver/example/notes/123/", "uuid": "123", "text": "foo bar"}
|
||||||
|
|
||||||
|
|
||||||
class TestTrailingSlashIncluded(TestCase):
|
class TestTrailingSlashIncluded(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user